关闭Javascript性能

时间:2011-07-07 17:23:07

标签: javascript performance closures

var name = function(n) {
    var digits = ['one','two','three','four'];
    return digits[n];
}

var namenew = (function() {
    digits = ['one','two','three','four'];
    return function(n) {
        return digits[n];
    }
}());

两个版本都会产生相同的输出,但据说第二个版本比第一个版本快得多。

据我所知,第一个版本每次执行该函数,而第二个版本存储执行结果。这就是我作为功能/常规OOPS程序员的困惑。

如何使用内部上下文保存函数?引擎盖下发生了什么?有人可以澄清一下吗?

2 个答案:

答案 0 :(得分:13)

这个问题的真正答案大约是3页。但我尽量让它尽可能短。 ECMA- / Javascript完全是Execution ContextsObject。 ECMAscript中有三种基本类型的上下文:Global contextFunction contextseval contexts

每次调用函数时,引擎都会在它自己的function context中生成它。此外,还创建了一个名为Activation object的名称。这个神秘的对象是function context的一部分,它至少包含:

  • [[范围链]]
  • 激活对象
  • “此”上下文值

不同引擎上可能有更多属性,但这三个属性都是ES的任何实现所必需的。但是,回到主题。如果调用了函数上下文,则将所有parent contexts(或更准确地说,来自父上下文的Activation objects)复制到[[Scope]]属性中。您可以将此属性视为一个包含(Activation-)对象的数组。现在,任何与函数相关的信息都存储在Activation对象中(形式参数,变量,函数声明)。

在您的示例中,digits变量存储在namenew的Activation对象中。第二个是在创建内部匿名函数时,它将Activation object添加到其[[Scope]]个属性中。当您在那里调用digits[n]时,Javascript首先尝试在其拥有激活对象中找到该变量。如果失败,则搜索进入Scopechain。瞧,我们找到了变量,因为我们从外部函数中复制了AO。

我已经写了太多简短的答案,但要真正给出这个问题的答案,你必须在这里解释一些关于ES的基本知识。我想这足以让你知道“幕后真正发生了什么”(还有很多要知道的,如果你想阅读更多内容我会给你一些参考资料)。


你问过它,你明白了:

http://dmitrysoshnikov.com/ecmascript/javascript-the-core/

答案 1 :(得分:9)

第一个函数每次执行时都会重新创建digits。如果它是一个大阵列,这是不必要的昂贵。

第二个函数将digits存储在仅与namenew共享的上下文中。每次namenew执行时,它只执行一次操作:return digits[n]

这样的例子不会在性能上有任何显着的提升,但是对于非常大的数组/对象/函数调用,性能将得到显着提升。

在OOP透视图中,以这种方式使用闭包类似于将数据存储在静态变量中。


不要忘记namenew正在接收闭包函数的结果。闭包本身只执行一次