5

最近我讀到這個performance guide Let's make the web faster,並被「避免陷阱與封閉」的建議困惑(如果這些建議是給變量範圍是動態的CommonLisp用戶):Javascript:爲什麼訪問閉包變量可能會很慢

var a = 'a'; 
function createFunctionWithClosure() { 
    var b = 'b'; 
    return function() { 
    var c = 'c'; 
    a; 
    b; 
    c; 
    }; 
} 

var f = createFunctionWithClosure(); 
f(); 

當調用f,引用a比引用b,這是比參考c慢慢。

這是相當明顯的是,引用局部變量Çb更快,但如果iterpreter編寫正確(不帶動態範圍界定 - 像鏈式散列表查找。)的轉速差應該只有邊緣。或不?

回答

4

你說得對。現代JS引擎將優化scope chain lookupprototype chain lookup。意思是說,AFAIK引擎會在下面存儲一些帶有訪問節點的哈希表。

這僅如果沒有eval()(顯式或隱式地,例如setTimeout)或try-catch條款或a with statement調用的工作原理。由於這樣的結構,解釋器不能確定如何訪問數據,它需要「回退」到經典scope chain lookup這意味着它必須爬過所有父上下文variable/activation objects並嘗試解析搜索到的變量名稱。 當然,這個過程將花費更多時間來處理查找處理開始處的「遠處」的對象/名稱。這意味着,訪問global object上的數據將始終是最慢的。

在你的代碼段,用於a查找過程會是這樣

anonymous function -> Execution Context -> Activation Object (not found) 
anonymous function -> Execution Context -> [[ Scope ]] 
    - createFunctionWithClosure 
    - global scope 
createFunctionWithClosure -> Activation Object (not found) 
global scope -> Variable Object (found) 

所描述的查找過程是ECMAScript第四版262第三版。 ECMAscript第5版有一些根本性的變化。

+0

對於長壽(和我的好奇心),你能描述它在v5中的變化嗎? – Hogan 2012-02-12 14:02:14

+0

因此,如果我會在var匿名函數中使用'var d = eval(「this」);'範圍鏈查找將抓取所有上下文以獲取'a'的引用?或者只是將'this'分配給'd'? – headacheCoder 2012-04-23 09:21:23

+0

@ headacheCoder:如果代碼在某種「舊式」瀏覽器中運行,那麼這很有可能。但是,實際上你絕對不應該做這樣一個可怕的聲明:)尖端的瀏覽器甚至可以使用'eval'來優化事物,甚至可能依賴於'嚴格模式'。但是這些瀏覽器無論如何都要遵循ES5規範。 – jAndy 2012-04-23 09:27:38