如果我在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不是?
解决方法
引人入胜的问题.
privateFunction2在publicFunction的范围内,但publicFunction从未实际使用它.我相信你在调试器中看到的是因为V8(Chrome的JavaScript引擎)出于各种原因(包括最小化内存使用)优化了闭包内容.
从理论上讲,根据规范,publicFunction会关闭它所定义的范围内的所有符号(具有持久的引用).具体来说,为最外面的匿名函数调用创建了一个execution context,并且该执行上下文有一个lexical environment,其中一个关联的binding object,publicFunction有一个隐式的匿名引用.该绑定对象具有(在理论上)名称为publicFunction,privateFunction2和其他一些东西(参数等)的属性.
但问题是publicFunction实际上并没有引用除privateFunction1之外的任何东西,并且对于它的代码,它不能引用任何其他东西.为了引用其他任何东西,你必须改变它的代码,当然它们V8会做出不同的决定. publicFunction中的代码没有eval(字符串)或新的Function(字符串)调用,因此V8可以自由地对它引用的符号进行静态分析.这意味着,没有调试器,绑定对象保留那些其他属性没有任何意义.他们从未使用过.
由于V8是一个积极优化的编译器(是的,编译器),显然它从执行上下文的绑定对象中删除了死属性.
如果我向使用privateFunction2的publicFunction添加一些内容,那么我可以从控制台中引用它,就像我可以使用privateFunction1一样.