Javascript:为什么对闭包变量的访问可能会很慢

den*_*isL 5 javascript performance closures interpreter functional-programming

最近我读过这个性能指南让我们更快地使网络变得困惑并且被"避免关闭陷阱"建议所迷惑(好像这些建议是针对变量范围是动态的CommonLisp用户提供的):

var a = 'a';
function createFunctionWithClosure() {
  var b = 'b';
  return function () {
    var c = 'c';
    a;
    b;
    c;
  };
}

var f = createFunctionWithClosure();
f();
Run Code Online (Sandbox Code Playgroud)

f调用when时,引用a比引用慢b,这比引用慢c.

很明显,引用局部变量cb快,但是如果iterpreter写得正确(没有动态范围 - 类似于链式散列表查找......),速度差异应该只是边际.或不?

jAn*_*ndy 4

你说得对。现代 JS 引擎会对 之scope chain lookup类的进行prototype chain lookup很多优化。意思是,据我所知,引擎试图保存某种带有访问节点的哈希表。

仅当没有eval()(显式或隐式,例如setTimeout)或try-catch子句或a with statement调用时,这才有效。由于这样的构造,解释器无法确定如何访问数据,并且需要“回退”到经典模式,scope chain lookup这实际上意味着,它必须爬行所有父上下文variable / activation objects并尝试解析搜索到的变量名称。当然,对于距离查找处理开始位置“很远”的对象/名称,此过程将花费更多时间。这反过来意味着,访问数据global object总是最慢的。

在您的代码片段中,查找过程a如下

anonymous function -> Execution Context -> Activation Object (not found)
anonymous function -> Execution Context -> [[ Scope ]] 
    - createFunctionWithClosure
    - global scope
createFunctionWithClosure -> Activation Object (not found)
global scope -> Variable Object (found)
Run Code Online (Sandbox Code Playgroud)

所描述的查找过程适用于 ECMAscript Edition 262 第三版。ECMAscript 第 5 版有一些根本性的变化。