javascript 閉包內部機制

在初學JavaScript函數式編程的時候,常常會出現使人出乎意料的結果,而緣由,大都是因爲不理解JavaScript閉包引發的;理解JavaScript的閉包,能夠從JavaScript的閉包內部機制出發。html

函數:編程

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

結果:數組

0: function creatFunctions/result[i]()
1: function creatFunctions/result[i]()
2: function creatFunctions/result[i]()
3: function creatFunctions/result[i]()
4: function creatFunctions/result[i]()
5: function creatFunctions/result[i]()
6: function creatFunctions/result[i]()
7: function creatFunctions/result[i]()
8: function creatFunctions/result[i]()
9: function creatFunctions/result[i]()

這個函數會返回一組數組,應該每一個函數都應該返回對應的值;而出現結果的緣由就在於閉包不是當即執行的。閉包

一、閉包的概念

JavaScript高設中,閉包是指有權訪問另外一個函數做用域的中的變量的函數,建立閉包的形式,就是在函數的內部建立另外一個函數。函數式編程

function makeFunc() {
    var name = "Mozilla";
    function displayName() {
        alert(name);
    }
    return displayName;
}

var myFunc = makeFunc();
myFunc();//MDN

displayName就是一個閉包。函數

二、閉包的內部機制

閉包的內部機制在於理解做用域鏈,函數的執行環境,變量對象和活動對象;this

函數被調用時會建立一個執行環境,在執行環境中初始化該函數的活動對象、變量對象、和做用域鏈。其中,做用域鏈是指向當前執行環境可訪問的變量對象的指針,是一個由內而外的過程。以上述函數爲例;spa

因爲全部函數的執行環境底層都是在全局執行環境中,JavaScript在運行時,首先初始化活動對象,即函數自帶的arguments、this變量;全局變量makeFunc、myFunc會綁定到變量對象上;該執行環境初始化以後會推入棧中,此後會初始化函數makeFunc的局部變量,讀取局部變量'name';內部函數displayName的函數聲明;值得注意的是,每一個執行環境的內部屬性[[scope]] 保存當前執行環境可訪問的變量對象,由內而外,即內部函數始終能夠訪問外部函數直到全局環境的全部變量,而外部環境是沒法讀取內部函數變量對象的;這是因爲做用域鏈中定義的。指針

通常函數在執行完成後,會銷燬其執行環境,只保留全局執行環境中變量;可是在閉包中,因爲閉包並非當即執行,而是保存着內部函數執行須要的全部變量,包括內部變量和外部變量;在須要時再執行;函數執行完畢後;因爲內部匿名函數的做用於鏈依然引用這個活動對象;所以活動對象仍然會保存在內存中。code

三、閉包的缺陷

閉包只是對函數內部的活動對象的保留,JavaScript中對變量只能保存一個定義;即 i 只能保存一個值,也就是上例中 i=10;閉包不是當即執行,當閉包執行時;向上搜索函數用到的全部變量,而內存中保存的是最後一次i的值;所以 i=10;

閉包會引用包含它函數的做用域,所以比普通函數佔用更多的內存。

相關文章
相關標籤/搜索