首頁  >  文章  >  web前端  >  什麼是閉包

什麼是閉包

一个新手
一个新手原創
2017-09-08 13:12:501498瀏覽

什麼是閉包:

閉包是指有權存取另一個函數作用域的變數的函數。
–《javascript高階程式設計》

在这个函数fun2中可以访问另一个函数中的变量a,所以fun2()就是一个闭包。
function fun1 () { 
      var  a = 0; 
      function fun2 () {  
          console.log(a);  
      } 
      fun2(); }

  1.在定義函數外呼叫閉包的方法,逃離方式:

    (1).將內部函數指定給一個全域變數;

var globalVar; function outer() { 
      console.log(‘outer’); 
      function inner(){ 
          console.log(‘inner’); 
      } 
      globalVar = inner;       
      } outer(); // outer 
      globalVar(); // inner;

在這個例子中inner()透過全域變數的參考成功逃離,現在可以在全域中調用,而且可以引用outer()的變數

    (2).透過返回值來'營救'內部函數的引用

function outer() { 
      console.log(‘outer’); 
      function inner(){ 
          console.log(‘inner’); 
      }    
      return inner;       
      } 
      var fn = outer(); // outer 
      fn(); // inner;

在這個例子中inner()透過回傳值成功逃離,現在可以在全域中調用,而且可以引用outer()的變數

  2.在函數外調用閉包的影響:增加記憶體佔用;

    本來正常的情況下是函數調用結束之後函數的執行環境離開環境棧,定義的變數廢棄(廢棄與垃圾收集機制有關),活動變數(變數物件)會被銷毀,記憶體釋放。但是現在因為閉包的作用域鏈包含了外部函數的變數對象,外部函數的變數有可能再被引用,垃圾收集機制不會將外部函數的變數廢棄,在記憶體保留的外部函數的變數物件。這樣就加大了對記憶體的佔用。

  3.閉包與變數的關係:閉包中常見的誤區及解決技巧

    閉包保存的是包含函數的整個變數對象,所取得的外部物件變數為閉包被呼叫時刻的物件變量,一般為外部函數變數的最後一個值。

例:

function createFun() { 
      var result = []; 
      for ( var i = 0; i < 10; i++) { 
          result[i] = function() { 
              return i; 
          }; 
      } 
      return result; } var result = createFun(); console.log(result5); // 10

  這裡外部函數的回傳值為一個數組,數組值為不同函數(閉包)的引用,我們會誤以為每個閉包的呼叫的回傳值不同,但實際上每個函數都會傳回一樣的值。因為當閉包呼叫時,呼叫閉包的外部函數已經執行完畢,此時外部函數的變數物件中的i = 10,而我們閉包的回傳值為i,閉包會取得呼叫時的外部變數對象,此時的i為10。

解決:

function createFun() { 
      var result = []; 
      for ( var i = 0; i < 10; i++) { 
          result[i] = function(num) { 
              return function() { 
                     return num; 
              }; 
           }(i); 
      } 
      return result; } var result = createFun(); console.log(result5); // 5

  在循環中,我們定義了一個匿名數組,並將立即執行該匿名函數的結果賦給數組,這裡的匿名函數有一個參數num,每次將i作為參數傳遞給num,每次循環num都會得到不同的值,所以每次返回了不同的函數(區別在於num值不同),當在外部調用數組值時,會返回不同的值,與預期相符。 

  4. 注意閉包中this值

  首先,關於函數中this指向,我們應該知道this指向調用該函數的對象,若無明確調用對象則指向window對象。

  在閉包中容易弄錯的this指向,例:

var name = “window”; 
      var o = { 
          name: “object”, 
          getName: function() { 
              return function() { 
                  return this.name; 
              }; 
          } 
      }; console.log(o.getName()()); // window

  可以看出閉包this指向了全局對象,分析,可以把o.getName ()()寫成(o.getName())(),這個表達式相當於第一步先執行了o.getName(),這個函數回傳了一個匿名函數(閉包),然後在全域下執行了這個閉包,並不是透過物件o調用,所以this指向全域物件。

  5. 記憶體洩漏的問題,如何減少不必要的記憶體佔用

function assignHandler() { 
          var ele = documnet.getElementById(“somenode”); 
          ele.onclick = function() { 
              console.log(ele.id); 
          }; 
          }

  在上面的例子中定義ele的方法與匿名函數有關,於是ele保存了對匿名函數的引用,而閉包會引用包含函數也引用了ele對象,這樣就造成了對象的循環引用,ele元素(dom元素佔用內存較大)就一直保存在了內存中無法釋放,解決方法如下:

function assignHandler() { 
          var ele = documnet.getElementById(“somenode”); 
          var id = ele.id; 
          ele.onclick = function() { 
              console.log(id);    // 通过id值中介表面上解除了与ele的循环引用 
          }; 
          ele = null; // 手动解除引用 }

以上是什麼是閉包的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn