为什么Chromedebugging器认为封闭的局部variables是未定义的?

有了这个代码:

function baz() { var x = "foo"; function bar() { debugger; }; bar(); } baz(); 

我得到这个意外的结果:

在这里输入图像描述

当我更改代码时:

 function baz() { var x = "foo"; function bar() { x; debugger; }; bar(); } 

我得到了预期的结果:

在这里输入图像描述

另外,如果在内部函数中有任何eval的调用,我可以像我想要的那样访问我的variables(不pipe我传递给eval是什么)。

同时,在两种情况下,Firefox开发工具都会给出预期的行为。

怎么了Chrome浏览器,debugging器的行为比Firefox不太方便? 我已经观察到这种行为一段时间,直到并包括版本41.0.2272.43testing版(64位)。

Chrome的JavaScript引擎是否可以“平滑”function?

有趣的是,如果我添加了内部函数中引用的第二个variables, xvariables仍然是未定义的。

我明白,在使用交互式debugging器的时候,经常会出现范围和variables定义的怪癖,但是在我看来,根据语言规范,应该是这些怪癖的“最佳”解决scheme。 所以我很好奇,如果这是由于Chrome优化比Firefox更进一步。 而且这些优化是否可以在开发过程中很容易被禁用(也许他们应该在开发工具打开时被禁用)。

另外,我可以用断点和debugger语句来重现这一点。

我发现了一个v8的问题报告 ,正是关于你在问什么。

现在,总结一下这个问题报告中的内容…… v8可以将函数本地的variables存储在堆栈中, 或者存放在堆上的“上下文”对象中。 它将在堆栈上分配局部variables,只要该函数不包含任何引用它们的内部函数。 这是一个优化 。 如果任何内部函数引用了一个局部variables,那么这个variables将被放入一个上下文对象(即在堆上而不是在堆栈上)。 eval的情况是特殊的:如果它被一个内部函数调用, 所有的局部variables都放在上下文对象中。

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

debugging器不能检查堆栈上的那些variables。 关于debugging中遇到的问题,一位项目成员说 :

我能想到的唯一解决scheme是,只要devtools开启,我们将取消所有的代码,并用强制的上下文分配进行重新编译。 尽pipe如此,这会显着地降低devtools的性能。

下面是一个“如果任何内部函数引用variables,把它放在上下文对象中”的例子。 如果你运行这个命令,你将能够在debugger语句中访问x ,即使x只用于foo函数, 这个函数从来不会被调用

 function baz() { var x = "x value"; var z = "z value"; function foo () { console.log(x); } function bar() { debugger; }; bar(); } baz(); 

就像@Louis说的那样,它是由v8优化引起的,所以把它replace成debugger

 eval('debugger'); 

eval将采用当前块

我也注意到了这个在nodejs中。 我相信(我承认这只是一个猜测),当代码被编译时,如果x没有出现在bar ,它不会使barbar的范围内可用。 这可能使它稍微更有效率; 问题是有人忘了(或不在意),即使没有xbar ,你可能会决定运行debugging器,因此仍然需要从内部访问x bar

哇,真有趣!

正如其他人所提到的,这似乎与scope有关,但更具体地说,与debugger scope 。 当注入脚本在开发人员工具中进行评估时,似乎确定了一个ScopeChain ,这导致了一些怪癖(因为它被绑定到了inspector / debugger范围)。 你发布的变化是这样的:

(编辑 – 实际上,你在你原来的问题中提到这个, 哎呀,我的坏!

 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

我怀疑这与variables和函数提升有关。 JavaScript将所有variables和函数声明带到了它们所定义函数的顶部。更多信息请看: http : //jamesallardice.com/explaining-function-and-variable-hoisting-in-javascript/

我敢打赌,Chrome正在调用带有variables不可用的variables的断点,因为函数中没有其他东西。 这似乎工作:

 function baz() { var x = "foo"; function bar() { console.log(x); debugger; }; bar(); }