2011-07-07 52 views
15
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]; 
    } 
}()); 

這兩個版本都會產生相同的輸出,但是據說第二個版本比第一個版本快得多。關閉Javascript性能

據我所知,第一個版本每次都執行函數,第二個版本存儲執行結果。這就是我作爲一個功能/定期OOPS程序員的混淆。

如何保存一個函數的內部上下文?引擎蓋下發生了什麼?有人可以澄清一下嗎?

+1

它創建一個包含數字列表中的對象,再加上方法。 –

回答

13

這個問題的真正答案大概有3頁。但我儘量儘量縮短。 ECMA-/Javascript全部是關於Execution ContextsObject。 ECMAscript中有三種基本類型的Context:Global contextFunction contextseval contexts

每當你調用一個函數時,你的引擎都會產生它自己的function context。另外,還有一個叫做Activation object的創建。此神祕對象是function context它由出的一部分的至少:

  • [[作用域鏈]]
  • 激活對象
  • 「這個」上下文值

可能有更多的屬性在不同的引擎上,但是這三個對於ES的任何實現都是必需的。但是,回到主題。如果調用函數上下文,則將所有parent contexts(或更精確地說,來自父上下文的Activation objects)複製到[[Scope]]屬性中。你可以把這個屬性想象成一個數組,它包含(Activation-)對象。現在,任何與功能相關的信息都存儲在激活對象(形式參數,變量,函數聲明)中。

在您的示例中,digits變量存儲在namenew的激活對象中。第二次創建內部匿名函數時,它將Activation object添加到它的[[Scope]] propertys中。當你調用digits[n]有,使用Javascript首先嚐試找到其自己激活對象變量。如果失敗了,搜索將進入Scopechain。瞧,那裏我們找到了變量,因爲我們從外部函數複製的AO。

我已經寫了太多了簡短的回答,但要真正給出一個很好的回答這樣的問題,你要在這裏解釋一下關於ES的一些基本知識。我想這僅僅是足以讓你瞭解到底發生了什麼「引擎蓋下」(有很多事情需要知道,如果你想了解更多,我給你一些參考)。


你自找的,你得到它:

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

8

第一個函數每次執行時都會重新創建digits。如果它是一個龐大的陣列,這是不必要的昂貴。

第二個函數將digits存儲在僅與namenew共享的上下文中。每次執行namenew時,它只執行一次操作:return digits[n]

像這樣的一個例子不會顯示任何明顯的性能提升,但是對於非常大的數組/對象/函數調用,性能將顯着提高。

在OOP中,以這種方式使用閉包的方法類似於將數據存儲在靜態變量中。


不要忘記,namenew正在接收結果關閉功能。關閉本身只執行一次

+0

不幸的是,我知道你提到的所有。我正在尋找的是發生了什麼'引擎蓋下' – Kiran