Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/cmake/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 为什么Chrome调试器认为闭合局部变量未定义?_Javascript_Google Chrome_Google Chrome Devtools - Fatal编程技术网

Javascript 为什么Chrome调试器认为闭合局部变量未定义?

Javascript 为什么Chrome调试器认为闭合局部变量未定义?,javascript,google-chrome,google-chrome-devtools,Javascript,Google Chrome,Google Chrome Devtools,使用此代码: function baz() { var x = "foo"; function bar() { debugger; }; bar(); } baz(); 我得到了一个意想不到的结果: 当我更改代码时: function baz() { var x = "foo"; function bar() { x; debugger; }; bar(); } 我得到了预期的结果: 此外,如果在内部函数中有任何对eval的调用

使用此代码:

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优化得更远。以及这些优化是否可以在开发过程中轻松禁用(也许应该在开发工具打开时禁用?)


此外,我还可以使用断点以及
调试器
语句来重现这一点。

我怀疑这与变量和函数有关。JavaScript将所有变量和函数声明放在定义它们的函数的顶部。更多信息请点击此处:

我打赌Chrome调用断点时变量对作用域不可用,因为函数中没有其他内容。这似乎有效:

函数baz(){
var x=“foo”;
功能条(){
控制台日志(x);
调试器;
};
bar();

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

正如其他人提到的,这似乎与
范围相关,但更具体地说,与
调试器范围相关。在开发人员工具中评估注入的脚本时,它似乎确定了一个
范围链
,这导致了一些奇怪之处(因为它绑定到了检查器/调试器范围)。您发布内容的一个变体是:

(编辑-事实上,你在最初的问题中提到了这一点,我的错!)

对于雄心勃勃的人和/或好奇的人,请查看来源,看看发生了什么:

我发现了一款v8引擎,它正是您想要的

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

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

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

我能想到的唯一解决方案是,无论何时打开devtools,我们都会对所有代码进行除臭,并使用强制上下文分配重新编译。不过,如果启用了devtools,这将大大降低性能

下面是一个“如果任何内部函数引用变量,请将其放入上下文对象”的示例。如果运行此命令,您将能够访问
debugger
语句中的
x
,即使
x
仅在
foo
函数中使用,该函数从未调用过


就像@Louis说的,它是由v8优化引起的。 您可以将调用堆栈遍历到此变量可见的帧:

或将调试器替换为

eval('debugger');

eval
将删除当前块

可能它正在为您清除未使用的变量…markle976似乎在说
调试器行实际上不是从
栏内部调用的。因此,当堆栈跟踪在调试器中暂停时,请查看堆栈跟踪:堆栈跟踪中是否提到了
bar
函数?如果我是对的,那么stacktrace应该说它在第5行、第7行、第9行暂停了。我认为这与V8展平功能无关。我认为这只是一个怪癖;我不知道我是否会称之为虫子。我认为大卫下面的回答最有意义。同样,我也有同样的问题,我讨厌它。但是当我需要在控制台中有access闭包条目时,我会转到您可以看到范围的地方,找到闭包条目并打开它。然后右键单击所需的元素,然后单击“存储为全局变量”。控制台上附加了一个新的全局变量
temp1
,您可以使用它访问范围条目。谢谢!)我想知道FF有什么不同之处。从我作为开发人员的角度来看,FF体验
function baz() {
  var x = "x value";
  var z = "z value";

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

  function bar() {
    debugger;
  };

  bar();
}
baz();
eval('debugger');