在Closure中访问变量时,为什么Chrome调试器未定义?

时间:2016-09-07 04:17:46

标签: javascript google-chrome google-developer-tools

代码:

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();

yinner的范围内,甚至只有inner2从未使用过的x引用它。我在范围内检查了结果,yy在那里:

x and y in closure

但是当我在监视面板和控制台中检查变量时,我无法获得所有变量:

can't get y in watch panel

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

它类似于Why does Chrome debugger think closed local variable is undefined?但不一样。因为我的代码中的y确保ArrayList<MyPOGO> arraylist =new ArrayList(); MyPOGO myPogo1=new MyPogo("More Rockets","+1 attack"); MyPOGO myPogo2=new MyPogo("Better Lasers","+5 attack "); MyPOGO myPogo3=new MyPogo("Super Shield","+1 defense"); MyPOGO myPogo4=new MyPogo("Super Defense", "+5 defense"); arraylist.add(myPogo1); arraylist.add(myPogo2); arraylist.add(myPogo3); arraylist.add(myPogo); 位于闭包中。实际上我的问题与Louis's answer在该问题下相反。

1 个答案:

答案 0 :(得分:1)

您是范围优化内部机制的第一手观察者。范围优化是检查当前范围中使用的变量以及优化对未使用变量的访问。原因是因为在JIT编译javascript时生成的机器代码中,变量命名的整个概念都丢失了。但是,为了维护javascript兼容性,JIT编译器将使用的局部变量数组关联到每个javascript函数。请注意以下代码。

&#13;
&#13;
(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))
})();
&#13;
&#13;
&#13;

如上所示,Javascript是一种基于堆栈的基于语言的语言。如果Javascript不是作用域语言,那么函数中使用的变量将取决于函数执行位置的变量值。例如,如果没有范围,scopedOne将使用 | Ref1 | (NaN)中myVariable的值而不是 | Ref2 | ( 101)并将NaN记录到控制台。回到主要观点,在机器代码中,当调试器进入时,它只能找出内存中实际位置所使用的变量的位置,因为只有那些内存位置持久存储到机器代码,因为只使用了那些变量。其余变量的内存位置仍然是个谜。正如您所观察到的,这会产生次要的副作用,即在范围内使用未使用的变量&#34;隐藏&#34;到那个功能。但是,有一个解决方案。

要解决此问题,只需将debugger;语句包装在eval中,以强制浏览器对范围内的所有变量进行昂贵的变量查找。基本上,浏览器必须返回原始源代码,检查范围中变量的原始名称,并找出JIT生成的机器代码存储变量值的位置。打开开发人员工具并运行下面的代码段。然后转到&#34; Call Stack&#34;中的前一级。面板并观察变量y的值的可见性如何从eval内部的可见变为外部eval不可见。

&#13;
&#13;
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();
&#13;
&#13;
&#13;