为什么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, x
variables仍然是未定义的。
我明白,在使用交互式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
,它不会使bar
在bar
的范围内可用。 这可能使它稍微更有效率; 问题是有人忘了(或不在意),即使没有x
的bar
,你可能会决定运行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(); }