범위 내의 모든 변수 가져 오기


194

현재 자바 스크립트 범위에있는 모든 변수를 가져 오는 방법이 있습니까?


Camsoft에 대한 귀하의 답변을 다시하십시오 : 그것은 완전히 다른 질문입니다. 해결하기 위해 답변을 업데이트했습니다.
TJ Crowder

3
문서가 열악한 모호한 API로 작업하고 있기 때문에 더 구체적으로 도움이되지 않는 것은 일반적인 질문 일뿐입니다.
Ian

전역 변수를 의미합니다! 을 사용하여 열거 가능한 전역 변수를 표시 할 수 있습니다 for (v in this) alert(v);. 그러나 모든 세계가 열거 가능한 것은 아니며 열거 할 수없는 세계 목록을 얻는 표준 방법을 알지 못합니다.
Jason Orendorff 2016 년

2
@Jason-아니오, 질문은 분명합니다. 함수 내부 범위의 변수는 전역 변수, 포함 this, arguments매개 변수 및 범위를 둘러싸에 정의 된 모든 변수를.
Tim Down

2
이것이 내가 Perl의 기호 테이블을 놓친 이유입니다. 이것을 향후 Javascript 릴리스에 추가 할 계획입니까?
Dexygen

답변:


84

"범위 내"변수는 "스코프 체인"에 의해 결정되며 프로그래밍 방식으로는 액세스 할 수 없습니다.

자세한 내용은 (아주 많이) ECMAScript (JavaScript) 사양을 확인하십시오. 여기에 링크의 당신이 표준 사양 (PDF 파일)를 다운로드 할 수있는 공식 페이지, 그리고 여기에 하나 의 공식, 링크 가능한 HTML 버전.

귀하의 의견에 따라 Camsoft로 업데이트

이벤트 함수 범위 내의 변수 이벤트 함수를 호출하는 방식이 아니라 이벤트 함수를 정의한 위치에 따라 결정됩니다. 그러나this KennyTM이 지적한 내용 ( for (var propName in ____))을 따라 함수를 통해 사용할 수있는 기능 과 인수에 대한 유용한 정보를 찾을 수 있습니다 this. 그들이 당신에게 어떤 인수를 제공하는지 확실하지 않으면 arguments모든 함수에 대해 암시 적으로 정의 된 변수를 통해 찾을 수 있습니다 ).

따라서 함수를 정의하는 위치로 인해 범위 내에있는 것 외에도 다음을 수행하여 다른 방법으로 사용 가능한 다른 것을 찾을 수 있습니다.

var n, arg, name;
alert("typeof this = " + typeof this);
for (name in this) {
    alert("this[" + name + "]=" + this[name]);
}
for (n = 0; n < arguments.length; ++n) {
    arg = arguments[n];
    alert("typeof arguments[" + n + "] = " + typeof arg);
    for (name in arg) {
        alert("arguments[" + n + "][" + name + "]=" + arg[name]);
    }
}

더 유용한 정보를 얻기 위해 확장 할 수 있습니다.

그 대신 Chrome 개발 도구 (일반적으로 개발에 Chrome을 사용하지 않는 경우에도) 또는 Firebug (일반적으로 개발에 Firefox를 사용하지 않는 경우에도 ) 또는 Opera의 Dragonfly 와 같은 디버거를 사용합니다 또는 IE의 "F12 개발자 도구" 그들이 제공하는 JavaScript 파일을 읽어보십시오. 그리고 적절한 문서를 위해 머리 위로 두들겨보십시오. :-)


참고로 Chrome에는 Firebug와 비슷한 훌륭한 디버거가 있습니다 (위에 약간 더 많은 착빙이 있습니다).
스위블

4
@ 스위블 게임 : 아, 나는 Firefox의 개발자 도구를 Firefox + Firebug보다 선호합니다. 그들은 2010 년에 많이 돌아 오지 않았습니다. :-)
TJ Crowder

1
@tjcrowder 참으로! 나는 대답에 타임 스탬프가 얼마 전에 나타났습니다 :)
Swivel

98

모두가 " 아니오 "라고 대답하고 " 아니오 "가 정답이라는 것을 알고 있지만 실제로 함수의 로컬 변수 를 가져와야하는 경우에는 제한적인 방법이 있습니다.

이 기능을 고려하십시오.

var f = function() {
    var x = 0;
    console.log(x);
};

함수를 문자열로 변환 할 수 있습니다.

var s = f + '';

함수 소스를 문자열로 얻습니다.

'function () {\nvar x = 0;\nconsole.log(x);\n}'

이제 esprima 와 같은 구문 분석기를 사용하여 함수 코드를 구문 분석하고 로컬 변수 선언을 찾을 수 있습니다.

var s = 'function () {\nvar x = 0;\nconsole.log(x);\n}';
s = s.slice(12); // to remove "function () "
var esprima = require('esprima');
var result = esprima.parse(s);

다음을 사용하여 객체를 찾으십시오.

obj.type == "VariableDeclaration"

결과 ( console.log(x)아래에서 제거했습니다 ) :

{
    "type": "Program",
    "body": [
        {
            "type": "VariableDeclaration",
            "declarations": [
                {
                    "type": "VariableDeclarator",
                    "id": {
                        "type": "Identifier",
                        "name": "x"
                    },
                    "init": {
                        "type": "Literal",
                        "value": 0,
                        "raw": "0"
                    }
                }
            ],
            "kind": "var"
        }
    ]
}

Chrome, Firefox 및 Node에서 이것을 테스트했습니다.

그러나이 방법 의 문제점 은 함수 자체에 변수가 정의되어 있다는 것입니다. 예를 들면 다음과 같습니다.

var g = function() {
    var y = 0;
    var f = function() {
        var x = 0;
        console.log(x);
    };
}

y가 아닌 x에 액세스 할 수 있습니다 . 그러나 여전히 호출자 체인 (arguments.callee.caller.caller.caller)을 루프에서 사용하여 호출자 함수의 로컬 변수를 찾을 수 있습니다. 로컬 변수 이름이 모두 있으면 범위 변수가 있습니다. 변수 이름을 사용하면 간단한 평가를 통해 값에 액세스 할 수 있습니다.


7
원래 문제를 해결하는 데 탁월한 기술입니다. 공감할 가치가 있습니다.
deepelement

4
호출자의 변수는 반드시 범위 변수 일 필요는 없습니다. 또한 범위 변수가 반드시 호출 체인에있는 것은 아닙니다. 클로즈 된 변수는 정의 / 클로저 범위를 벗어난 (및 클로저의 본문으로 변수에 액세스 할 수없는) 호출자로부터 호출 할 때 클로저 함수에 의해 참조 될 수 있습니다.
DDS

"간단한 평가"를 명확하게 설명해 주시겠습니까? 아래 코드로 시도했지만 범위에 변수가 갇히지 못했습니다. function getCounter(start){ return function(){ start ++; return start; } } var counter = getCounter(1); var startInClosure = eval.call(counter, 'this.start;'); console.log(startInClosure);그것은 인쇄 undefined나는 그것이 2.되어야한다 기대하면서
Pylipala

@Pylipala 여기서 질문은 범위 밖의 변수가 범위 밖의 로컬 변수 값을 얻지 못하는 범위에 관한 것입니다. 외부에서는 액세스 할 수없는 로컬 변수의 정의이기 때문에 불가능합니다. 코드와 관련하여 컨텍스트가 범위가 아니지만 컨텍스트에 시작 을 넣지 않았으므로 this.start로 읽을 수 없습니다 . 여기를보십시오 : paste.ubuntu.com/11560449
iman

@iman 답변 주셔서 감사합니다. 또한 Javascript 측에서는 불가능하다고 생각하므로 v8 측에서는 가능하다고 생각합니다. 내 문제를 정확하게 설명하는 질문 링크 를 아래에서 찾았습니다 . Lasse Reichstein은 아니오라고 말하지만 mako-taco는 그렇습니다. C ++ 코드를 링크 로 시도했지만 작성 방법을 모릅니다.
Pylipala 2016 년

32

예, 아니오 거의 모든 상황에서 "아니오". 전역 범위를 확인하려는 경우 제한적인 방식으로 만 "예"를 사용하십시오. 다음 예를 보자.

var a = 1, b = 2, c = 3;

for ( var i in window ) {
    console.log(i, typeof window[i], window[i]);
}

어떤 출력 150 + 다른 것들 사이에 , 다음과 같은 :

getInterface function getInterface()
i string i // <- there it is!
c number 3
b number 2
a number 1 // <- and another
_firebug object Object firebug=1.4.5 element=div#_firebugConsole
"Firebug command line does not support '$0'"
"Firebug command line does not support '$1'"
_FirebugCommandLine object Object
hasDuplicate boolean false

따라서 현재 범위에서 일부 변수를 나열 할 수 있지만 신뢰할 수 있고 간결하거나 효율적이거나 쉽게 액세스 할 수있는 것은 아닙니다.

더 좋은 질문은 왜 어떤 변수가 범위 내에 있는지 알고 싶습니까?


2
나는 질문이 더 일반적이며 웹 브라우저의 맥락에서 자바 스크립트에만 국한되지 않는다고 생각합니다.
Radu Simionescu 2018 년

노드를 사용하는 경우 "글로벌"에 대해 "창"이라는 단어를 변경하거나 "this"라는 단어를 사용할 수 있지만 "엄격한 사용"에서는 금지되어 있습니다.
Ivan Castellanos

hasOwnProperty를 확인하는 줄을 추가했습니다. 예를 들면 다음과 같습니다 for ( var i in window ) { if (window.hasOwnProperty(i)) { console.log(i, window[i]); }}.. 이것은 적어도 상속 된 속성을 줄이고 변수는 약 50 개의 다른 속성 중 하나입니다.
timctran 2016 년

8
왜 누군가 디버깅 및 / 또는 개발 목적으로 범위에 속하는 변수를 확인하고 싶지 않아야합니까?
Dexygen

로컬 범위에 어떤 변수가 있는지 알고 싶은 또 다른 이유는 클로저를 직렬화하는 것입니다.
Michael

29

ECMAScript 6에서는 코드를 with프록시 객체 로 명령문 내부에 배치하여 어느 정도 가능 합니다. 엄격하지 않은 모드가 필요하고 나쁜 습관입니다.

function storeVars(target) {
  return new Proxy(target, {
    has(target, prop) { return true; },
    get(target, prop) { return (prop in target ? target : window)[prop]; }
  });
}
var vars = {}; // Outer variable, not stored.
with(storeVars(vars)) {
  var a = 1;   // Stored in vars
  var b = 2;   // Stored in vars
  (function() {
    var c = 3; // Inner variable, not stored.
  })();
}
console.log(vars);

프록시는 내부 with에서 참조 된 모든 식별자를 소유한다고 주장 하므로 변수 할당이 대상에 저장됩니다. 조회의 경우 프록시는 프록시 대상 또는 전역 개체 (부모 범위가 아닌)에서 값을 검색합니다. letconst변수는 포함되어 있지 않습니다.

영감을받은 이 대답 하여 BERGI .


1
이러한 간단한 기술에는 놀라 울 정도로 성공적입니다.
Jonathan Eunice

WOW 슈퍼 파워
페리 미몬

16

당신은 할 수 없습니다.

변수, 함수 선언의 식별자 및 함수 코드에 대한 인수는 변수 Object의 특성으로 바인딩되며 이는 불가능합니다.

또한보십시오:


1
그러나 범위 내 변수는 현재 변수 개체를 뛰어 넘습니다. 범위 내 변수는 범위 체인에 의해 결정됩니다. 범위 체인 은 일련의 변수 객체로 구성되고 (일반적인 경우) 전역 객체로 끝나는 with체인입니다 (단, 명령문을 사용하여 체인에 다른 객체를 삽입 할 수는 있음).
TJ Crowder

bclary.com에 대한 링크는 +1입니다. ECMA 웹 사이트에 다음 몇 달 안에 최신 사양의 HTML 버전이 표시 될 것입니다.
TJ Crowder

3
참고로 두 링크가 모두 끊어졌습니다.
0xc0de

당신은 CAN - 정적 분석 때와 jsfiddle.net/mathheadinclouds/bvx1hpfn/11
mathheadinclouds

8

특정 범위에서 Var에 액세스하는 가장 간단한 방법

  1. 개발자 도구> 리소스 (Chrome)를 엽니 다.
  2. 해당 범위에 액세스 할 수있는 기능으로 파일 열기 (파일을 찾으려면 cmd / ctrl + p 팁)
  3. 해당 함수 내에 중단 점을 설정하고 코드를 실행하십시오.
  4. 중단 점에서 중지되면 콘솔 (또는 범위 var 창)을 통해 범위 var에 액세스 할 수 있습니다.

참고 : 축소되지 않은 js에 대해이 작업을 수행하려고합니다.

모든 비 개인 전용 변수를 표시하는 가장 간단한 방법

  1. 콘솔 열기 (Chrome)
  2. 유형 : this.window
  3. 엔터

이제 선언 된 모든 객체로 확장 할 수있는 객체 트리가 표시됩니다.


7

모두가 알다시피 : 당신은 할 수 없습니다. 그러나 obj를 만들고 선언 한 모든 var를 해당 obj에 할당 할 수 있습니다. 이렇게하면 var를 쉽게 확인할 수 있습니다.

var v = {}; //put everything here

var f = function(a, b){//do something
}; v.f = f; //make's easy to debug
var a = [1,2,3];
v.a = a;
var x = 'x';
v.x = x;  //so on...

console.log(v); //it's all there

1
멋진 예제 덕분에 +1 감사합니다. 완성을 console.log(window); 위해서만 jsfiddle.net/4x3Tx
Stano

5

나는 iman에 의해 요약 된 아이디어 위에 (본질적으로) 바이올린을 만들었습니다 . 다음은 두 번째 ipsum 위로 마우스를 가져갈 때의 모습입니다.return ipsum*ipsum - ...

여기에 이미지 설명을 입력하십시오

범위 내에있는 변수는 선언 된 위치에 강조 표시됩니다 (범위에 따라 다른 색상으로). lorem빨간색 테두리가 그림자가 변수입니다 (범위에 있지만, 범위에있을 더 트리 아래 다른가 lorem는 없을 것입니다하지 않을 경우.)

나는 esprima 라이브러리를 사용하여 JavaScript와 estraverse, escodegen, escope (esprima 위에 유틸리티 라이브러리)를 구문 분석하고 있습니다.

작동 원리

ast = esprima.parse(sourceString, {range: true, sourceType: 'script'});

추상 구문 트리를 만듭니다. 그때,

analysis = escope.analyze(ast);

프로그램의 모든 범위에 대한 정보를 캡슐화하는 복잡한 데이터 구조를 생성합니다. 나머지는 해당 분석 개체 (및 추상 구문 트리 자체)로 인코딩 된 정보를 수집하여 대화 형 색 구성표를 만듭니다.

정답은 실제로 "아니오"가 아니라 "그렇지만"입니다. "하지만"큰 것 : 기본적으로 JavaScript에서 크롬 브라우저 (및 devtools)의 상당 부분을 다시 작성해야합니다. JavaScript는 Turing 완전한 언어이므로 원칙적으로 가능합니다. 불가능한 것은 소스 코드 전체를 문자열로 사용하지 않고 전체를 수행 한 다음 매우 복잡한 작업을 수행하는 것입니다.


3

디버그를 돕기 위해 변수를 수동으로 검사하려면 디버거를 시작하십시오.

debugger;

브라우저 콘솔로 바로 연결됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.