为什么 Chrome 调试器在访问 Closure 中的变量时会出现未定义的情况? [复制]

2024-01-13

Code:

function test4() {
    var x = 10;
    var y = 100;
    // inner referred x only
    function inner () {
        console.log(x);
        debugger;
    }
    // inner2 referred y to make sure y is in the scope of inner
    function inner2 () {
        console.log(y);
    }
    return inner;
}
var foo = test4();
foo();

y是在范围内inner甚至只是inner2从未使用过的请参考它。我检查了范围内的结果并x, y在那儿:

但是当我检查手表面板和控制台中的变量时,我无法获取所有变量:

奇怪的是y位于范围内,但在使用调试器时未定义。 那么,这是否意味着调试器无法访问当前上下文中未使用的变量,即使它在闭包中,还是只是一个错误? (我的chrome版本是51.0.2704.103 m)

它类似于为什么 Chrome 调试器认为封闭的局部变量未定义? https://stackoverflow.com/q/28388530/6799379但不一样。因为inner2在我的代码中确保y是在闭包中。实际上我的问题与路易斯的回答 https://stackoverflow.com/a/28431346/6799379在这个问题下。


您是范围优化内部机制的第一手观察者。作用域优化是检查当前作用域中使用了哪些变量,并优化对未使用变量的访问。这样做的原因是因为在 JavaScript 的 JIT 编译生成的机器代码中,变量命名的整个概念丢失了。但是,为了保持 javascript 合规性,JIT 编译器将一组已使用的局部变量与每个 javascript 函数相关联。请观察以下代码。

(function(){
  "use strict";
  var myVariable = NaN; // |Ref1|
  var scopedOne = (function(){
    var myVariable = 101; // |Ref2|
    return x => x * myVariable;
  })();
  var scopedTwo = (function(){
    var myVariable = -7; // |Ref3|
    return x => x / myVariable;
  })();
  console.log("scopedOne(2):  ", scopedOne(2));
  console.log("scopedTwo(56): ", scopedTwo(56))
})();

如上所示,Javascript 是一种基于作用域堆栈的语言。如果 Javascript 不是作用域语言,那么函数中使用的变量将取决于函数执行位置处的变量值。例如,如果没有范围,scopedOne将使用的值myVariable at |Ref1|(NaN) 而不是 at|Ref2|(101) 并且会记录NaN到控制台。回到要点,在机器代码中,当调试器进入时,它只能找出已使用变量在内存中的实际位置,因为只有这些内存位置已持久保存到机器代码中,因为只有这些变量已被使用。其余变量的存储位置对它来说仍然是个谜。正如您所观察到的,这具有使作用域中未使用的变量对该函数“不可见”的次要副作用。不过,有一个解决方案。

要避免这个问题,只需将debugger;eval 中的语句强制浏览器对作用域中的所有变量进行昂贵的变量查找。基本上,浏览器必须返回原始源代码,检查作用域中变量的原始名称,并找出 JIT 生成的机器代码存储变量值的位置。打开开发人员工具并运行下面的代码片段。然后进入上一级的“Call Stack”面板,观察变量值的可见性如何y从内部可见的变化eval到看不见的外面eval.

function test4() {
    var x = 10;
    var y = 100;
    // inner referred x only
    function inner () {
        console.log(x);
        eval("debugger;");
    }
    // inner2 referred y to make sure y is in the scope of inner
    function inner2 () {
        console.log(y);
    }
    return inner;
}
var foo = test4();
foo();
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 Chrome 调试器在访问 Closure 中的变量时会出现未定义的情况? [复制] 的相关文章

随机推荐