1. 程式人生 > 實用技巧 >JavaScript——對閉包的看法,為什麼要用閉包?說一下閉包原理以及應用場景

JavaScript——對閉包的看法,為什麼要用閉包?說一下閉包原理以及應用場景

前言

  • 閉包是什麼
  • 閉包原理是什麼
  • 閉包優缺點
  • 閉包應用場景

步驟

1)什麼是閉包

函式執行後返回結果是一個內部函式,並被外部變數所引用,如果內部函式持有被執行函式作用域的變數,即形成了閉包。

可以在內部函式訪問到外部函式作用域。使用閉包,一可以讀取函式中的變數,二可以將函式中的變數儲存在記憶體中,保護變數不被汙染。而正因閉包會把函式中的變數值儲存在記憶體中,會對記憶體有消耗,所以不能濫用閉包,否則會影響網頁效能,造成記憶體洩漏。當不需要使用閉包時,要及時釋放記憶體,可將內層函式物件的變數賦值為null。

2)閉包原理

函式執行分成兩個階段(預編譯階段和執行階段)。

  • 在預編譯階段,如果發現內部函式使用了外部函式的變數,則會在記憶體中建立一個“閉包”物件並儲存對應變數值,如果已存在“閉包”,則只需要增加對應屬性值即可。
  • 執行完後,函式執行上下文會被銷燬,函式對“閉包”物件的引用也會被銷燬,但其內部函式還持用該“閉包”的引用,所以內部函式可以繼續使用“外部函式”中的變數

利用了函式作用域鏈的特性,一個函式內部定義的函式會將包含外部函式的活動物件新增到它的作用域鏈中,函式執行完畢,其執行作用域鏈銷燬,但因內部函式的作用域鏈仍然在引用這個活動物件,所以其活動物件不會被銷燬,直到內部函式被燒燬後才被銷燬。

3)優點

  1. 可以從內部函式訪問外部函式的作用域中的變數,且訪問到的變數長期駐紮在記憶體中,可供之後使用
  2. 避免變數汙染全域性
  3. 把變數存到獨立的作用域,作為私有成員存在

4)缺點

  1. 對記憶體消耗有負面影響。因內部函式儲存了對外部變數的引用,導致無法被垃圾回收,增大記憶體使用量,所以使用不當會導致記憶體洩漏
  2. 對處理速度具有負面影響。閉包的層級決定了引用的外部變數在查詢時經過的作用域鏈長度
  3. 可能獲取到意外的值(captured value)

4)應用場景

應用場景一: 典型應用是模組封裝,在各模組規範出現之前,都是用這樣的方式防止變數汙染全域性。

var Yideng = (function () {
    // 這樣宣告為模組私有變數,外界無法直接訪問
    var foo = 0;

    function Yideng() {}
    Yideng.prototype.bar = function bar() {
        return foo;
    };
    return Yideng;
}());

應用場景二: 在迴圈中建立閉包,防止取到意外的值。

如下程式碼,無論哪個元素觸發事件,都會彈出 3。因為函式執行後引用的 i 是同一個,而 i 在迴圈結束後就是 3

for (var i = 0; i < 3; i++) {
    document.getElementById('id' + i).onfocus = function() {
      alert(i);
    };
}
//可用閉包解決
function makeCallback(num) {
  return function() {
    alert(num);
  };
}
for (var i = 0; i < 3; i++) {
    document.getElementById('id' + i).onfocus = makeCallback(i);
}