閉包如何導致記憶體洩漏以及如何防止?
閉包
Javascript 的優勢之一是閉包。Javascript 允許巢狀函式(一個函式在另一個函式內部)訪問父函式的變數。這個由內部函式訪問外部函式變數的過程稱為閉包。當宣告的變數自動可用於內部巢狀函式並在記憶體中駐留,即使它在內部巢狀函式中沒有被引用時,就會發生記憶體洩漏。
在下面的例子中,'childFunction' 是在外部函式 'parentFunction' 內定義的內部函式。當用引數 "outer val" 呼叫 'parentFunction' 時,外部變數 a 將被賦值為 "outer val"。該函式返回一個指向內部函式 "childFunction" 的指標,該指標包含在變數 'val' 中。
即使外部函式已返回,外部函式的區域性變數 a 仍然存在。在 Javascript 中,一旦呼叫 parentFunction,就會建立一個具有屬性 'a' 的作用域物件。此屬性包含 arg1 的值,也稱為 "outer val"。類似地,當 parentFunction 返回時,它將返回內部函式 (childFunction),該函式包含在變數 val 中。
由於內部函式持有對外部函式變數的引用,因此具有屬性 'a' 的作用域物件將不會被垃圾回收。
示例
<html> <body> <script> window.onload= function parentFunction(arg1) { var a = arg1; return function childFunction (arg2) { alert( a +" "+ arg2); }; }; var val = parentFunction("outer val"); val("inner val"); </script> </body> </html>
避免記憶體洩漏
新增另一個函式
透過新增另一個函式,將有兩個內部函式。由於有兩個內部函式,因此沒有函式可以引用外部函式的變數,從而完全停止閉包。
當沒有閉包時,記憶體洩漏的可能性就會減少。
示例
<html> <body> <script> window.onload=function parentFunction(){ var Obj1 = function childFunction1() { document.write("the leak is avoided"); }; (function childFunction2(){ var obj2 = document.getElementById("closure"); obj2.onclick=Obj1 })(); }; </script> <input type = "button" id="closure" value ="Click Here"> </body> </html>
程式碼執行後,將顯示如下按鈕
按下按鈕後,我們將得到如下輸出
輸出
the leak is avoided
廣告