javascript 閉包內部機制

在初學JavaScript函數式編程的時候,經常會出現令人出乎意料的結果,而原因,大都是由於不理解JavaScript閉包引起的;理解JavaScript的閉包,可以從JavaScript的閉包內部機制出發。

函數:

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]()

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

1、閉包的概念

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

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

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

displayName就是一個閉包。

2、閉包的內部機制

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

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

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

一般函數在執行完成後,會銷燬其執行環境,只保留全局執行環境中變量;但是在閉包中,由於閉包並不是立即執行,而是保存着內部函數執行需要的所有變量,包括內部變量和外部變量;在需要時再執行;函數執行完畢後;由於內部匿名函數的作用於鏈依然引用這個活動對象;因此活動對象仍然會保存在內存中。

3、閉包的缺陷

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

閉包會引用包含它函數的作用域,因此比普通函數佔用更多的內存。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章