閉包如何導致記憶體洩漏以及如何防止?


閉包

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

更新於:2019年7月30日

2K+ 次瀏覽

啟動您的職業生涯

透過完成課程獲得認證

開始
廣告