Kir*_*ran 15 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];
}
}());
Run Code Online (Sandbox Code Playgroud)
两个版本都会产生相同的输出,但据说第二个版本比第一个版本快得多.
据我所知,第一个版本每次执行该函数,因为第二个版本存储执行结果.这就是我作为功能/常规OOPS程序员的困惑.
如何用内部上下文保存函数?引擎盖下发生了什么?有人可以澄清一下吗?
jAn*_*ndy 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变量存储在Activation对象中namenew.第二个是在创建内部匿名函数时,它将其添加Activation object到其[[Scope]]属性中.当你digits[n]在那里打电话时,Javascript首先尝试在自己的 Activation对象中找到该变量.如果失败,则搜索进入Scopechain.瞧,我们找到了变量,因为我们从外部函数复制了AO.
我已经写了太多的简短回答,但要真正给出这个问题的一个好答案,你必须在这里解释一些关于ES的基本知识.我想这足以让你知道"引擎盖下"真正发生了什么(还有很多要知道,如果你想阅读更多,我会给你一些参考).
你问它,你得到它:
http://dmitrysoshnikov.com/ecmascript/javascript-the-core/
第一个函数digits每次执行时都会重新创建.如果它是一个大阵列,这是不必要的昂贵.
第二个函数存储digits在仅与之共享的上下文中namenew.每次namenew执行它只执行一次操作:return digits[n].
像这样的例子不会在性能上有任何显着的提升,但是对于非常大的数组/对象/函数调用,性能将得到显着提高.
在OOP透视图中,以这种方式使用闭包类似于将数据存储在静态变量中.
不要忘记namenew收到封闭功能的结果.闭包本身只执行一次.