讀JavaScript高階程式設計系列之一(你所不知道的閉包)

wuliDream發表於2017-12-08

從定義上講

  • 閉包是有權訪問另一個函式作用域值中的變數的函式。

建立的閉包常見方式

  • 就是再一個函式內部建立另一個函式
在理解閉包之前,我們不忙先理解下作用域鏈
  • 作用域鏈本質上是 一個指向變數物件的指標列表,它只引用但不實際包含變數物件。
  • 無論什麼時候在函式中訪問一個變數時,就會從作用域鏈中搜尋具有相應名字的變數。一般來講, 當函式執行完畢後,區域性活動物件就會被銷燬,記憶體中僅儲存全域性作用域(全域性執行環境的變數物件)。 但是,閉包的情況又有所不同。

接下來出現活動物件這一概念:

  • 在一個函式物件被呼叫的時候,會建立一個活動物件,首先將該函式的每個形參和實參,都新增為該活動物件的屬性和值;將該函式體內顯示宣告的變數和函式,也新增為該活動的的屬性(在閉包內指外部函式)
  • ​ 然後將這個活動物件做為該函式執行環境的作用域鏈的最前端,並將這個函式物件的[[scope]]屬性裡作用域連結入到該函式執行環境作用域鏈的後端。(閉包內這個函式指:內部函式)

一般而言,普通的函式呼叫,不含閉包情況:

  • 全域性環境的物件始終存在,而像函式內的區域性環境的變數物件,則只有在函式執行的過程中存在。
  • 在建立函式時,會建立一個預先包含全域性變數物件的作用域鏈,這個作用域鏈被儲存在內部的[[Scope]]屬性中。
  • 當呼叫函式時,會為函式建立一個執行環境,然後通過複製函式的[[Scope]]屬性中的物件構建起執行環境的作用域鏈。
含閉包函式的呼叫:
  • 在另一個函式內部定義的函式會將包含函式(即外部函式)的活動物件新增到它的作用域鏈中。
  • 在匿名函式,從外部函式呼叫中被返回後,它的作用域鏈被初始化為包含外部函式的活動物件和全域性變數物件。這樣,匿名函式就可以訪問在外部函式中定義的所有變數。更為重要的是,外部函式在執行完畢後,其活動物件也不會被銷燬,因為匿名函式的作用域鏈仍然在引用這個活動物件。換 句話說,當外部函式呼叫後,其執行環境的作用域鏈會被銷燬,但它的活 動物件仍然會留在記憶體中;直到匿名函式被銷燬後,外部函式的活動物件才會 被銷燬。 

閉包中使用this會導致一些問題

  • 在閉包中使用 this 物件也可能會導致一些問題。我們知道,this 物件是在執行時基於函式的執 行環境繫結的:在全域性函式中,this 等於 window,而當函式被作為某個物件的方法呼叫時,this 等 於那個物件。不過,匿名函式的執行環境具有全域性性,因此其 this 物件通常指向 window。但有時候 由於編寫閉包的方式不同,這一點可能不會那麼明顯
  • 記憶體洩露
  • 。。。


相關文章