调试显示模块模式:在调用之前,函数不在范围内?

时间:2013-02-13 12:47:29

标签: javascript scope closures google-chrome-devtools

如果我在Chrome开发者工具中运行此代码:

var test = (function () {

  var publicFunction,
      privateFunction1,
      privateFunction2;

  privateFunction1 = function privateFunction1() {
    return true;
  };

  privateFunction2 = function privateFunction2() {
    return true;
  };

  publicFunction = function publicFunction() {
    privateFunction1();
    debugger;
  };

  return {
    publicFunction: publicFunction
  };
})();

为什么privateFunction1在断点处的范围内,而privateFunction2不是?

Screenshot of Chrome Dev Tools

1 个答案:

答案 0 :(得分:4)

引人入胜的问题。

privateFunction2范围内的

publicFunction ,但publicFunction从未实际使用过它。我相信你在调试器中看到的是因为V8(Chrome的JavaScript引擎)出于各种原因(包括最小化内存使用)优化了闭包内容。

理论上,根据规范,publicFunction关闭(具有持久引用)范围内所有符号的符号。具体来说,为最外层匿名函数的调用创建了一个execution context,并且该执行上下文有一个lexical environment,其中publicFunction有一个隐含的,匿名的binding object参考。该绑定对象具有(理论上)名称publicFunctionprivateFunction1privateFunction2以及其他一些事物(arguments等)的属性。

但问题是publicFunction实际上并没有引用除privateFunction1之外的任何内容,并且对于它的代码,不能引用任何其他内容。为了引用其他任何东西,你必须改变它的代码,当然它们V8会做出不同的决定。 publicFunction中的代码没有eval(string)new Function(string)个调用,因此V8可以自由对其引用的符号进行静态分析。这意味着,如果没有调试器,对绑定对象保持其他属性没有任何意义。它们从未使用过。

由于V8是一个积极优化的编译器(是的,编译器),显然它会从执行上下文的绑定对象中删除死属性。

如果我向publicFunction添加使用privateFunction2的内容,我可以在控制台中引用它,就像我privateFunction1一样。