Javascript:为啥访问闭包变量可能很慢

Posted

技术标签:

【中文标题】Javascript:为啥访问闭包变量可能很慢【英文标题】:Javascript: why the access to closure variable might be slowJavascript:为什么访问闭包变量可能很慢 【发布时间】:2012-03-04 04:08:39 【问题描述】:

最近我读到了这个performance guide Let's make the web faster,对“避免使用闭包的陷阱”的建议感到困惑(好像这些建议是为变量范围是动态的 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 快,但是如果正确编写了迭代器(没有动态范围 - 类似于链式哈希表查找..)速度差异应该只是微不足道的。还是不行?

【问题讨论】:

【参考方案1】:

你是对的。现代 JS 引擎将优化 scope chain lookupprototype chain lookup 很多。意思是,AFAIK 引擎试图在下面保存某种带有访问节点的哈希表。

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

在您的 sn-p 中,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 版有一些根本性的变化。

【讨论】:

为了长寿(和我的好奇心),您能描述一下它在 v5 中的变化吗? 那么如果我在匿名函数内部做var d = eval("this");,作用域链查找将爬取所有上下文以获取a的引用?还是只是将this 分配给d @headacheCoder:如果该代码在某种“老式”浏览器中运行,这是很有可能的。然而,你实际上不应该做出如此糟糕的声明:) 尖端浏览器甚至可以使用eval 优化事物,甚至可能依赖于strict mode。但是这些浏览器无论如何都遵循 ES5 规范。

以上是关于Javascript:为啥访问闭包变量可能很慢的主要内容,如果未能解决你的问题,请参考以下文章

javascript闭包

JavaScript 闭包

javascript--特权方法

JavaScript 闭包

JavaScript 作用域和闭包

JavaScript闭包