1. 程式人生 > >js的閉包中關於執行環境和作用鏈的理解

js的閉包中關於執行環境和作用鏈的理解

style 帶頭結點 理解 result name http script 不同 參數

首先講一講執行環境:

  執行環境按照字面上來理解就是指目前代碼執行所在的環境。

當JavaScript代碼執行的時候,會進入不同的執行上下文,這些執行上下文會構成了一個執行上下文棧(Execution context stack,ECS)。

執行環境的分類

  •   全局執行環境:

    在瀏覽器中,其指window對象,是JS代碼開始運行時的默認環境。
    全局執行環境的變量對象始終都是作用域鏈中的最後一個對象。

  •   函數執行環境:

    當某個函數被調用時,會先創建一個執行環境及相應的作用域鏈。然後使用arguments和其他命名參數的值來初始化執行環境的變量對象。當該函數執行完之後會將該函數的執行環境彈出棧。

  註:上述分類解釋也表明了js中只有兩種作用域,即全局作用域和函數局部作用域,不存在塊作用域。

執行環境的組成

  一個執行環境包括變量對象,內部[[Scope]]屬性,this指針這三個屬性

  技術分享圖片

  (註意:圖片來源於簡書——理解js的執行環境)

  • 變量對象(Variable object,VO): 變量對象即包含變量的對象,使用包含的變量來初始化變量對象,除了我們無法訪問它外,和普通對象沒什麽區別(全局執行環境的變量對象就是window,我們可以訪問window)。
  • [[Scope]]屬性:作用域即變量對象,作用域鏈是一個由變量對象組成的帶頭結點的單向鏈表,其主要作用就是用來進行變量查找。而[[Scope]]屬性是一個指向這個鏈表頭節點的指針。
  • this: 指向一個環境對象,註意是一個對象,而且是一個普通對象,而不是一個執行環境。

完全是小白的可能不太清楚作用域鏈,然後補充一下作用域鏈:

  在前面提到過,當代碼在一個環境中執行時,會創建變量對象的一個作用域鏈。作用域鏈的用途是保證對該執行環境有權訪問的所有變量和函數的有序訪問

  作用域鏈包含了執行環境棧中的每個執行環境對應的變量對象

  在訪問一個變量時,先在作用域鏈表上的第一個變量對象上查找。如果沒有找到則繼續在作用域鏈上的第二個變量對象上查找。直至搜索到全局執行環境的變量對象即Window對象。

  

  那麽再看看閉包的特殊性訪問,

  

function returnfunc (propertyName) {
  return function (obj) {             //-----這行定義並返回了一個閉包,也被稱之為一個匿名函數
    return obj[propertyName];         //這裏用方括號法訪問屬性,因為屬性是變量(returnfunc()函數的參數)
  };
}

var savefunc = returnfunc("name");     //調用returnfunc()
var result = savefunc({name:"Picasso"});//調用savefunc()
alert(result);                        //返回字符串“Picasso”

作者:閉家鎖
鏈接:https://www.zhihu.com/question/36393048/answer/71879330
來源:知乎
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請註明出處。

(註意:以下圖片來源於知乎——理解活動對象和變量對象的區別)

以上代碼的最開始的作用域鏈和執行環境:

技術分享圖片

我們先開始調用returnfunc()函數,馬上會創建一個包含returnfunc()變量對象的行環境,作用域鏈開始變化,如下圖:

技術分享圖片

圖的白色虛線表示執行程序產生的效果,它可能表示的是返回一個結果、復制某種值、產生一個新物體、建立某種聯系等。

隨後returnfunc()函數會返回它內部的匿名函數,當匿名函數被返回並執行後,整個作用域鏈和執行環境又發生了變化:

技術分享圖片

可以看到,returnfunc函數在返回內部函數之後其執行環境就不存在了,但是其活動對象仍然在內存中,並沒有被銷毀;按照前面講過的一句話“作用域鏈包含了執行環境棧中的每個執行環境對應的變量對象。”來看,當returnfunc的執行環境不存在之後,其所包含的活動對象是應該會被銷毀。事實上,直到匿名函數被銷毀,returnfunc的活動對象才會被銷毀。這是閉包的特殊性,在匿名函數從returnfunc中被返回後,它的作用域鏈被初始化為包含returnfunc函數的活動對象和全局變量對象,即使returnfunc函數的執行環境被彈出棧,因為匿名函數的作用域鏈仍然在引用returnfunc函數的活動對象,returnfunc函數的活動對象仍然在內存中,這樣匿名函數就可以訪問returnfunc函數中定義的所有變量。

以上內容學習自:

  1.知乎——理解活動對象和變量對象的區別

  2.簡書——理解js的執行環境

  3.csdn——js的執行環境和作用域

js的閉包中關於執行環境和作用鏈的理解