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

Javascript: why the access to closure variable might be slow

本文关键字:访问 变量 为什么 闭包 Javascript      更新时间:2023-09-26

最近我读了这本性能指南让我们让web更快,并对"避免闭包陷阱"的建议感到困惑(就好像这些建议是为变量作用域是动态的CommonLisp用户提供的一样):

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

当调用f时,引用a比引用b慢,后者比引用c

很明显,引用局部变量cb快,但如果iterprepter写得正确(没有动态作用域,比如链式哈希表查找…),那么速度差异应该只是很小的。还是不?

你说得对。现代JS引擎将对scope chain lookupprototype chain lookup进行大量优化。意味着,AFAIK引擎试图保存某种下面有访问节点的哈希表。

只有当没有调用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)

所描述的查找过程适用于ECMAscript Edition 262第3版。ECMAscript第5版有一些基本的更改