Chrome 디버거가 닫힌 로컬 변수가 정의되지 않은 이유는 무엇입니까?


167

이 코드로 :

function baz() {
  var x = "foo";

  function bar() {
    debugger;
  };
  bar();
}
baz();

이 예기치 않은 결과가 나타납니다.

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

코드를 변경하면 :

function baz() {
  var x = "foo";

  function bar() {
    x;
    debugger;
  };
  bar();
}

예상 결과를 얻습니다.

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

또한 eval내부 함수 내에 호출이 있으면 원하는대로 변수에 액세스 할 수 있습니다 (전달하는 대상은 중요하지 않습니다 eval).

한편, Firefox 개발 도구는 두 상황 모두에서 예상되는 동작을 제공합니다.

Chrome에서 디버거가 Firefox보다 편리하게 작동하지 않는 것은 무엇입니까? 버전 41.0.2272.43 베타 (64 비트)를 포함하여 한동안이 동작을 관찰했습니다.

Chrome의 자바 스크립트 엔진이 가능한 한 기능을 "평평하게 만드는"것입니까?

I는 제 2 가변 흥미롭게 경우 추가 되어 내부에서 참조를 함수의 x변수는 아직 정의되지 않는다.

대화 형 디버거를 사용할 때 범위와 변수 정의가있는 단점이 있음을 이해하지만 언어 사양에 따라 이러한 단점에 대한 "최상의"솔루션이 있어야합니다. Chrome이 Firefox보다 더 최적화되어 있기 때문에 궁금합니다. 또한 개발 중에 이러한 최적화를 쉽게 비활성화 할 수 있는지 여부 (개발 도구가 열려있을 때 비활성화해야합니까?)

또한 debugger문장 뿐만 아니라 중단 점으로 이것을 재현 할 수 있습니다 .


2
어쩌면 그것은 당신을 위해 당신의 길에서 사용되지 않은 변수를 얻고있을 것입니다 ...
dandavis

markle976은 debugger;라인이 실제로 inside에서 호출되지 않았다고 말합니다 bar. 따라서 디버거에서 일시 중지 될 때 스택 추적을 살펴보십시오. 스택 추적에 bar함수가 언급되어 있습니까? 내가 옳다면, 스택 트레이스는 라인 (9)에서, 7 호선에서 5 호선에서 일시 정지 있어요 말해야한다
데이비드 Knipe

V8 병합 기능과 관련이 있다고 생각하지 않습니다. 나는 이것이 기발한 것이라고 생각한다. 심지어 버그라고 부르는지 모르겠습니다. 아래의 다윗의 대답이 가장 합리적이라고 생각합니다.
markle976


2
나는 같은 문제가 있습니다. 그러나 콘솔에 액세스 클로저 항목이 필요하면 범위를 볼 수있는 곳으로 이동하여 클로저 항목을 찾아서여 십시오. 그런 다음 필요한 요소를 마우스 오른쪽 단추로 클릭 하고 전역 변수로 저장을 클릭하십시오 . 새로운 전역 변수 temp1가 콘솔에 연결되며이를 사용하여 범위 항목에 액세스 할 수 있습니다.
Pablo

답변:


149

나는 당신이 요구하는 것에 관한 v8 이슈 보고서 를 발견했습니다 .

이제 해당 이슈 보고서에서 말한 내용을 요약하면 ... v8은 함수의 로컬 변수를 스택 또는 힙에있는 "컨텍스트"개체에 저장할 수 있습니다 . 함수에 변수를 참조하는 내부 함수가 포함되어 있지 않으면 스택에 로컬 변수를 할당합니다. 최적화 입니다. 경우 모든 내부 함수는 로컬 변수를 참조,이 변수 (힙 대신 스택 IE) 콘텍스트 객체에 넣어지게된다. 의 경우 eval는 특별합니다. 내부 함수에 의해 전혀 호출되지 않으면 모든 로컬 변수가 컨텍스트 객체에 배치됩니다.

컨텍스트 객체의 이유는 일반적으로 외부 함수에서 내부 함수를 반환 할 수 있으며 외부 함수가 실행되는 동안 존재하는 스택을 더 이상 사용할 수 없기 때문입니다. 따라서 내부 함수가 액세스하는 것은 외부 함수에서 생존하고 스택이 아닌 힙에 있어야합니다.

디버거는 스택에있는 변수를 검사 할 수 없습니다. 디버깅에서 발생하는 문제와 관련하여 한 프로젝트 멤버 다음과 같이 말합니다 .

내가 생각할 수있는 유일한 해결책은 devtools가 켜질 때마다 모든 코드를 선택 해제하고 강제 컨텍스트 할당으로 다시 컴파일한다는 것입니다. devtools를 사용하면 성능이 크게 저하됩니다.

다음은 "내부 함수가 변수를 참조하는 경우 컨텍스트 객체에 넣습니다"의 예입니다. 이것을 실행하면 결코 호출되지 않는 함수 에서만 사용 되지만 명령문 x에서 액세스 할 수 있습니다 !debuggerxfoo

function baz() {
  var x = "x value";
  var z = "z value";

  function foo () {
    console.log(x);
  }

  function bar() {
    debugger;
  };

  bar();
}
baz();

13
코드를 선택 해제하는 방법을 알고 있습니까? 디버거를 REPL로 사용하고 거기서 코드를 내 파일로 전송하는 것을 좋아합니다. 그러나 접근 할 수없는 변수로 실현 가능하지 않은 경우가 많습니다. 간단한 평가는 그렇게하지 않습니다. 무한한 for 루프가 들릴 수 있습니다.
Ray Foss

디버깅하는 동안 실제로이 문제에 부딪치지 않았으므로 코드를 선택 해제하는 방법을 찾지 못했습니다.
Louis

6
문제의 마지막 의견은 다음과 같이 말합니다 : 모든 것이 강제로 컨텍스트 할당되는 모드로 V8을 넣는 것이 가능하지만 Devtools UI통해 트리거하는 방법 /시기가 확실하지 않습니다 디버깅을 위해 때로는 그렇게하고 싶습니다. . 그러한 모드를 어떻게 강제 할 수 있습니까?
Suma

2
@ user208769 중복으로 닫을 때 미래 독자에게 가장 유용한 질문을 선호합니다. 어떤 질문이 가장 유용한 지 결정하는 데 도움이되는 여러 가지 요소가 있습니다. 질문에는 정확히 0 개의 답변이 있고이 질문에는 여러 개의 상향식 답변이 있습니다. 따라서이 질문은이 둘 중 가장 유용합니다. 유용성이 대부분 같은 경우에만 날짜가 결정 요인이됩니다.
Louis

1
이 답변은 실제 질문 (왜)에 대한 답변이지만 암묵적인 질문입니다. 코드에 추가 참조를 추가하지 않고 디버깅을 위해 사용되지 않는 컨텍스트 변수에 액세스하는 방법은 무엇입니까? -아래 @OwnageIsMagic으로 더 잘 대답합니다.
Sigfried

30

@Louis와 마찬가지로 v8 최적화로 인해 발생했습니다. 이 변수가 표시되는 프레임으로 콜 스택을 통과 할 수 있습니다.

call1 call2

또는 교체 debugger와 함께

eval('debugger');

eval 현재 청크를 해제합니다


1
거의 훌륭합니다! contents가있는 VM 모듈 (노란색)에서 일시 중지되며 debugger컨텍스트를 실제로 사용할 수 있습니다. 실제로 디버깅하려는 코드에 대해 스택을 한 수준 높이면 컨텍스트에 액세스 할 수 없게됩니다. 따라서 숨겨진 클로저 변수에 액세스하는 동안 디버깅중인 코드를 볼 수 없으므로 약간 어색합니다. 그래도 디버깅에 적합하지 않은 코드를 추가하지 않아도되므로 전체 앱을 최적화하지 않고 전체 컨텍스트에 액세스 할 수 있기 때문에 공감할 것입니다.
Sigfried

아 .... 황색의 eval소스 창을 사용하여 컨텍스트에 액세스하는 것보다 훨씬 복잡합니다. 코드를 단계별로 진행할 수 없습니다 (단계를 밟고 eval('debugger')싶은 모든 줄 사이에 두지 않는 한 )
Sigfried

적절한 스택 프레임으로 이동 한 후에도 특정 변수가 보이지 않는 상황이있는 것 같습니다. 나는 controllers.forEach(c => c.update())어딘가에 깊은 곳에서 브레이크 포인트를 쳤다 c.update(). 그런 다음 controllers.forEach()호출 된 프레임을 선택하면 controllers정의되지 않습니다 (그러나 해당 프레임의 다른 모든 것이 표시됩니다). 최소한의 버전으로 재현 할 수 없었습니다. 복잡해야 할 임계 값이 있거나 무언가가 필요하다고 생각합니다.
PeterT

@PeterT <undefined> 인 경우 잘못된 위치에 있거나 somewhere deep inside c.update()코드가 비
동기화되고

6

나는 또한 nodejs에서 이것을 발견했습니다. 코드가 컴파일 될 때 x안에 bar나타나지 않으면 x의 범위 내에서 사용할 수 없다고 생각합니다 (그리고 나는 단지 추측 일뿐 입니다) bar. 이것은 아마도 조금 더 효율적일 것입니다. 문제는 xin 이없는 경우에도 bar디버거를 실행하여 여전히 x내부 에서 액세스해야한다는 것을 잊어 버린 사람 bar입니다.


2
감사. 기본적으로 나는 이것을 "디버거 거짓말"보다 자바 스크립트 초보자에게 더 잘 설명하고 싶다.
Gabe Kopley

@GabeKopley : 기술적으로 디버거가 거짓말을하지 않습니다. 변수가 참조되지 않으면 기술적으로 묶이지 않습니다. 따라서 인터프리터가 클로저를 만들 필요가 없습니다.
slebetman

7
그것은 요점이 아니다. 디버거를 사용할 때 외부 범위에서 변수의 값을 알고 싶어하는 상황이 자주 있었지만 그로 인해 불가능했습니다. 더 철학적으로 말하자면 디버거가 거짓말하고 있다고 말할 것입니다. 변수가 내부 범위에 존재하는지 여부는 실제로 사용되는지 또는 관련되지 않은 eval명령 이 있는지에 따라 달라지지 않아야합니다 . 변수가 선언되면 액세스 할 수 있어야합니다.
David Knipe

2

와, 정말 재미 있어요!

다른 사람들이 언급했듯이 이것은와 관련이 scope있지만 더 구체적 으로 관련이있는 것 같습니다 debugger scope. 주입 된 스크립트가 개발자 도구에서 평가되면을 결정하는 것 같습니다 ScopeChain. 검사기 / 디버거 범위에 바인딩되어 있기 때문에 약간의 기묘함이 발생합니다. 게시 한 내용의 변형은 다음과 같습니다.

(편집-실제로, 당신은 당신의 원래 질문, 이케, 내 나쁜 점 에서 이것을 언급합니다 ! )

function foo() {
  var x = "bat";
  var y = "man";

  function bar() {
    console.log(x); // logs "bat"

    debugger; // Attempting to access "y" throws the following
              // Uncaught ReferenceError: y is not defined
              // However, x is available in the scopeChain. Weird!
  }
  bar();
}
foo();

야심적이고 호기심이 많은 사람들을 위해 소스를 조사해보십시오.

https://github.com/WebKit/webkit/tree/master/Source/JavaScriptCore/inspector https://github.com/WebKit/webkit/tree/master/Source/JavaScriptCore/debugger


0

나는 이것이 변수 및 기능 호이 스팅과 관련이 있다고 생각합니다. JavaScript는 모든 변수 및 함수 선언을 정의 된 함수의 최상위로 가져옵니다. 추가 정보 : http://jamesallardice.com/explaining-function-and-variable-hoisting-in-javascript/

함수에 다른 것이 없기 때문에 Chrome이 범위에서 사용할 수없는 변수로 중단 점을 호출한다고 확신합니다. 이것은 작동하는 것 같습니다 :

function baz() {
  var x = "foo";

  function bar() {
    console.log(x); 
    debugger;
  };
  bar();
}

이것처럼 :

function baz() {
  var x = "foo";

  function bar() {
    debugger;
    console.log(x);     
  };
  bar();
}

희망, 및 / 또는 위의 링크가 도움이됩니다. 이들은 내가 좋아하는 SO 질문 중 하나입니다, BTW :)


감사! :) FF가 어떻게 다른지 궁금합니다. 개발자로서 나의 관점에서 볼 때, FF 경험은 ... 객관적으로 더 나은
게이브 Kopley

2
"lex time에 중단 점을 호출"의심합니다. 이것이 브레이크 포인트가 아닙니다. 그리고 함수에 다른 것들이없는 것이 왜 중요한지 알지 못합니다. nodejs와 같은 것이면 중단 점은 매우 버그가있을 수 있습니다.
David Knipe
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.