【问题标题】:Javascript performance with closure带有闭包的 Javascript 性能
【发布时间】:2011-07-07 17:23:06
【问题描述】:
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 程序员感到困惑的地方。

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

【问题讨论】:

  • 它正在创建一个包含数字列表的对象,以及一个方法。

标签: javascript performance closures


【解决方案1】:

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

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

  • [[作用域链]]
  • 激活对象
  • “this”上下文值

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

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

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


你要它,你得到它:

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

【讨论】:

    【解决方案2】:

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

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

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

    从 OOP 的角度来看,以这种方式使用闭包类似于将数据存储在静态变量中。


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

    【讨论】:

    • 很遗憾,我理解你所说的一切。我正在寻找的是“幕后”正在发生的事情
    • IMO 从 OOP 的角度来看,这种类型的闭包更像是一个单例;它被构建一次,存储它的状态,并提供访问。但是这两个类比都不完美。但问题本身可以概括为“闭包是如何工作的?”该示例分散了这一点,因为第一个函数应该更像var digits = ['one','two','three','four']; var name = function(n) { return digits[n]; },实际上在功能上是等效的。提到“据说第二个版本要快得多”只会混淆这一点。
    猜你喜欢
    • 2020-01-29
    • 2021-10-16
    • 1970-01-01
    • 2018-07-19
    • 2020-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-07
    相关资源
    最近更新 更多