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程序员的困惑。
如何使用内部上下文保存函数?引擎盖下发生了什么?有人可以澄清一下吗?
答案 0 :(得分:13)
这个问题的真正答案大约是3页。但我尽量让它尽可能短。 ECMA- / Javascript完全是Execution Contexts
和Object
。 ECMAscript中有三种基本类型的上下文:Global context
,Function contexts
和eval 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的基本知识。我想这足以让你知道“幕后真正发生了什么”(还有很多要知道的,如果你想阅读更多内容我会给你一些参考资料)。
你问过它,你明白了:
答案 1 :(得分:9)
第一个函数每次执行时都会重新创建digits
。如果它是一个大阵列,这是不必要的昂贵。
第二个函数将digits
存储在仅与namenew
共享的上下文中。每次namenew
执行时,它只执行一次操作:return digits[n]
。
这样的例子不会在性能上有任何显着的提升,但是对于非常大的数组/对象/函数调用,性能将得到显着提升。
在OOP透视图中,以这种方式使用闭包类似于将数据存储在静态变量中。
不要忘记namenew
正在接收闭包函数的结果。闭包本身只执行一次。