Javascript 为什么 Chrome 调试器认为关闭的局部变量未定义?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28388530/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why does Chrome debugger think closed local variable is undefined?
提问by Gabe Kopley
With this code:
使用此代码:
function baz() {
var x = "foo";
function bar() {
debugger;
};
bar();
}
baz();
I get this unexpected result:
我得到了这个意想不到的结果:


When I change the code:
当我更改代码时:
function baz() {
var x = "foo";
function bar() {
x;
debugger;
};
bar();
}
I get the expected result:
我得到了预期的结果:


Also, if there is any call to evalwithin the inner function, I can access my variable as I want to do (doesn't matter what I pass to eval).
此外,如果eval在内部函数中有任何调用,我可以按照我的意愿访问我的变量(与我传递给 的内容无关eval)。
Meanwhile, Firefox dev tools give the expected behavior in both circumstances.
同时,Firefox 开发工具在这两种情况下都能提供预期的行为。
What's up with Chrome that the debugger behaves less conveniently than Firefox? I have observed this behavior for some time, up to and including Version 41.0.2272.43 beta (64-bit).
Chrome 调试器的行为不如 Firefox 方便,这是怎么回事?我已经观察了一段时间的这种行为,直到并包括版本 41.0.2272.43 beta(64 位)。
Is it that Chrome's javascript engine "flattens" the functions when it can?
Chrome 的 javascript 引擎是否在可能的情况下“扁平化”了这些功能?
Interestingly if I add a second variable that isreferenced in the inner function, the xvariable is still undefined.
有趣的是,如果我添加第二可变是在内部功能引用,则x变量仍然不确定。
I understand that there are often quirks with scope and variable definition when using an interactive debugger, but it seems to me that based on the language specification there ought to be a "best" solution to these quirks. So I am very curious if this is due to Chrome optimizing further than Firefox. And also whether or not these optimizations can easily be disabled during development (maybe they ought to be disabled when dev tools are open?).
我知道在使用交互式调试器时,范围和变量定义经常有怪癖,但在我看来,基于语言规范,应该有一个“最佳”解决方案来解决这些怪癖。所以我很好奇这是否是由于 Chrome 比 Firefox 进一步优化。以及这些优化是否可以在开发过程中轻松禁用(也许应该在开发工具打开时禁用它们?)。
Also, I can reproduce this with breakpoints as well as the debuggerstatement.
另外,我可以用断点和debugger语句重现这一点。
采纳答案by Louis
I've found a v8 issue reportwhich is precisely about what you're asking.
我找到了一个 v8问题报告,它正是关于你要问的。
Now, To summarize what is said in that issue report... v8 can store the variables that are local to a function on the stack orin a "context" object which lives on the heap. It will allocate local variables on the stack so long as the function does not contain any inner function that refers to them. It is an optimization. If anyinner function refers to a local variable, this variable will be put in a context object (i.e. on the heap instead of on the stack). The case of evalis special: if it is called at all by an inner function, alllocal variables are put in the context object.
现在,总结一下该问题报告中所说的内容……v8 可以将函数本地的变量存储在堆栈上或存在于堆上的“上下文”对象中。只要函数不包含任何引用它们的内部函数,它就会在堆栈上分配局部变量。这是一种优化。如果任何内部函数引用了一个局部变量,这个变量将被放在一个上下文对象中(即在堆上而不是在堆栈上)。的情况eval很特殊:如果它被内部函数调用,则所有局部变量都放在上下文对象中。
The reason for the context object is that in general you could return an inner function from the outer one and then the stack that existed while the outer function ran won't be available anymore. So anything the inner function accesses has to survive the outer function and live on the heap rather than on the stack.
上下文对象的原因是,通常您可以从外部函数返回一个内部函数,然后在外部函数运行时存在的堆栈将不再可用。因此,内部函数访问的任何内容都必须在外部函数中存活并存在于堆中而不是堆栈中。
The debugger cannot inspect those variables that are on the stack. Regarding the problem encountered in debugging, one Project Member says:
调试器无法检查堆栈中的那些变量。关于调试中遇到的问题,一位项目成员说:
The only solution I could think of is that whenever devtools is on, we would deopt all code and recompile with forced context allocation. That would dramatically regress performance with devtools enabled though.
我能想到的唯一解决方案是,无论何时启用 devtools,我们都会取消选择所有代码并使用强制上下文分配重新编译。但是,启用 devtools 会显着降低性能。
Here's an example of the "if any inner function refers to the variable, put it in a context object". If you run this you'll be able to access xat the debuggerstatement even though xis only used in the foofunction, which is never called!
这是“如果有任何内部函数引用该变量,则将其放入上下文对象中”的示例。如果您运行它,您将能够访问xatdebugger语句,即使x仅在从未调用的foo函数中使用!
function baz() {
var x = "x value";
var z = "z value";
function foo () {
console.log(x);
}
function bar() {
debugger;
};
bar();
}
baz();
回答by OwnageIsMagic
回答by David Knipe
I've also noticed this in nodejs. I believe (and I admit this is only a guess) that when the code is compiled, if xdoes not appear inside bar, it doesn't make xavailable inside the scope of bar. This probably makes it slightly more efficient; the problem is someone forgot (or didn't care) that even if there's no xin bar, you might decide to run the debugger and hence still need to access xfrom inside bar.
我也在 nodejs 中注意到了这一点。我相信(我承认这只是猜测),当代码被编译,如果x不出现里面bar,它不会使x可用的范围内bar。这可能使它稍微更有效率;问题是有人忘记(或不在乎)即使没有xin bar,您也可能决定运行调试器,因此仍然需要x从内部访问bar。
回答by Hyman
Wow, really interesting!
哇,真的很有趣!
As others have mentioned, this seems to be related to scope, but more specifically, related to debugger scope. When injected script is evaluated in the developer tools, it seems to determine a ScopeChain, which results in some quirkiness (since it's bound to the inspector/debugger scope). A variation of what you posted is this:
正如其他人所提到的,这似乎与 相关 scope,但更具体地说,与 相关debugger scope。当在开发人员工具中评估注入的脚本时,它似乎确定了 a ScopeChain,这会导致一些古怪(因为它绑定到检查器/调试器范围)。您发布的内容的一个变体是:
(EDIT - actually, you mention this in your original question, yikes, my bad!)
(编辑 - 实际上,您在最初的问题中提到了这一点,哎呀,我的错!)
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();
For the ambitious and/or curious, scope (heh) out the source to see what's going on:
对于雄心勃勃和/或好奇的人,请查看(heh)来源以查看发生了什么:
https://github.com/WebKit/webkit/tree/master/Source/JavaScriptCore/inspectorhttps://github.com/WebKit/webkit/tree/master/Source/JavaScriptCore/debugger
https://github.com/WebKit/webkit/tree/master/Source/JavaScriptCore/inspector https://github.com/WebKit/webkit/tree/master/Source/JavaScriptCore/debugger
回答by markle976
I suspect this has to do with variable and function hoisting. JavaScript brings all variable and function declarations to the top of the function they are defined in. More info here: http://jamesallardice.com/explaining-function-and-variable-hoisting-in-javascript/
我怀疑这与变量和函数提升有关。JavaScript 将所有变量和函数声明带到定义它们的函数的顶部。更多信息在这里:http: //jamesallardice.com/explaining-function-and-variable-hoisting-in-javascript/
I bet that Chrome is calling the break point with the variable unavailable to the scope because there is nothing else in the function. This seems to work:
我敢打赌,Chrome 正在使用作用域不可用的变量调用断点,因为函数中没有其他内容。这似乎有效:
function baz() {
var x = "foo";
function bar() {
console.log(x);
debugger;
};
bar();
}
As does this:
就像这样:
function baz() {
var x = "foo";
function bar() {
debugger;
console.log(x);
};
bar();
}
Hope this, and / or the link above helps. These are my favorite kind of SO questions, BTW :)
希望这个和/或上面的链接有帮助。这些是我最喜欢的 SO 问题,顺便说一句:)

