Chrome调试器为何认为封闭的局部变量未定义?

2020/10/24 11:01 · javascript ·  · 0评论

使用此代码:

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 beta(64位)。

Chrome的JavaScript引擎是否可以“拉平”功能?

有趣的是,如果我添加内部函数中引用的第二个变量,x变量仍未定义。

我了解到,使用交互式调试器时,通常会有范围和变量定义的怪癖,但在我看来,根据语言规范,应该为这些怪癖提供“最佳”解决方案。所以我很好奇这是否是由于Chrome比Firefox更优化了。以及是否可以在开发过程中轻松禁用这些优化(是否应该在打开开发工具时将其禁用?)。

另外,我可以使用断点和debugger语句来重现此内容

我找到了一份v8问题报告,该报告正是您的要求。

现在,总结一下该问题报告中的内容... v8可以将函数局部变量存储在堆栈上存在于堆中的“上下文”对象中。只要函数不包含任何引用它们的内部函数,它将在堆栈上分配局部变量。这是一个优化如果任何内部函数引用局部变量,则此变量将放入上下文对象中(即放在堆中而不是堆栈中)。的情况eval很特殊:如果内部函数完全调用它,则所有局部变量都将放在上下文对象中。

使用上下文对象的原因是,通常您可以从外部函数中返回一个内部函数,然后在外部函数运行时存在的堆栈将不再可用。因此,内部函数访问的任何内容都必须在外部函数中生存,并生存在堆中而不是栈中。

调试器无法检查堆栈上的那些变量。关于调试中遇到的问题,一位项目成员

我能想到的唯一解决方案是,每当打开devtools时,我们将取消所有代码并使用强制上下文分配重新编译。但是,启用devtools会大大降低性能。

这是“如果内部函数引用了变量,则将其放在上下文对象中”的示例。如果运行此命令x,则debugger即使x仅在foo函数中使用语句,也可以对其进行访问函数从不调用

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

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

  function bar() {
    debugger;
  };

  bar();
}
baz();

就像@Louis所说,它是由v8优化引起的。您可以遍历“调用”堆栈以显示该变量所在的帧:

通话1
通话2

或替换debugger

eval('debugger');

eval 将取消当前块

我在nodejs中也注意到了这一点。我相信(我承认这只是猜测),当代码被编译,如果x不出现里面bar,它不会使x可用的范围内bar这可能使其效率更高。问题是有人忘记了(或不在乎)即使没有xin bar,您也可能决定运行调试器,因此仍然需要x从内部访问bar

哇,真有趣!

正如其他人提到的那样,这似乎与 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

我怀疑这与变量和函数提升有关。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问题,顺便说一句:)

本文地址:http://javascript.askforanswer.com/chromediaoshiqiweiherenweifengbidejububianliangweidingyi.html
文章标签: ,   ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!