讀古今文學網 > 編寫高質量代碼:改善JavaScript程序的188個建議 > 建議155:小心閉包導致內存洩漏 >

建議155:小心閉包導致內存洩漏

閉包是JavaScript最強大的一個方面,它允許函數訪問局部範圍之外的數據。在複雜的網頁應用中閉包無處不在。有一種性能影響與閉包有關。為了分析與閉包有關的性能問題,考慮下面的例子:


function assignEvents{

var;

document.getElementById("save-btn").onclick=function(event){

saveDocument(id);

};

}


assignEvents函數為一個DOM元素指定了一個事件處理句柄。此事件處理句柄是一個閉包,當assignEvents被執行時,可以訪問其範圍內部的id變量。要用這種方法封閉對id變量的訪問,必須創建一個特定的作用域鏈。

當assignEvents被執行時,一個激活對像被創建,其中包含了一些應有的內容,比如id變量,它將成為運行期上下文作用域鏈上的第一個對象,全局對象是第二個。當閉包被創建時,scope屬性與這些對像一起被初始化。

由於閉包的scope屬性包含與運行期上下文作用域鏈相同的對象引用,因此會產生副作用。通常,一個函數的激活對象與運行期上下文一同被銷毀。當涉及閉包時,激活對象就無法被銷毀了,因為引用仍然存在於閉包的scope屬性中。這意味著與腳本中的非閉包涵數相比,閉包需要更多內存開銷。在大型網頁應用中,這可能是個問題,尤其在IE中更被關注。IE使用非本地JavaScript對像實現DOM對象,閉包可能導致內存洩漏。

當閉包被執行時,一個運行期上下文將被創建,它的作用域鏈與在scope中引用的兩個相同的作用域鏈同時被初始化,然後一個新的激活對像作為閉包自身被創建。

注意,在閉包中使用的兩個標識符:id和saveDocument,它們存在於作用域鏈第一個對像之後的位置上。這是閉包最主要的性能關注點:經常訪問一些範圍之外的標識符,每次訪問都導致一些性能損失。

在腳本中最好小心地使用閉包,內存和運行速度都值得去關注。但是,可以將常用的域外變量存入局部變量中,然後直接訪問局部變量,這樣能夠減小對運行速度的影響。