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

jan*_*oeh 7 javascript closures scope 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
  };
})();
Run Code Online (Sandbox Code Playgroud)

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

Chrome Dev Tools的屏幕截图

T.J*_*der 4

有趣的问题。

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

理论上,根据规范,publicFunction封闭(具有持久引用)其定义范围内的所有符号。具体来说,为调用最外层的匿名函数创建了一个执行上下文,并且该执行上下文具有一个词法环境,该环境具有关联的绑定对象,该对象publicFunction具有隐式的匿名引用。该绑定对象具有(理论上)名称publicFunctionprivateFunction1privateFunction2和一些其他内容(arguments等等)的属性。

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

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

如果我添加一些可以publicFunction用于privateFunction2任何用途的东西,我就可以像我一样从控制台引用它privateFunction1