閉包

剛開始接觸閉包時,被閉包搞得頭暈目眩,就知道閉包是函數裏面嵌套函數,看了視頻查閱了書籍之後明白了閉包的原理及作用。

理解閉包首先要先理解執行環境和作用域鏈。執行環境定義了變量或函數有權訪問的其他數據,決定了它們的行爲。每個函數都有自己的執行環境,當執行流進入一個函數時,函數的環境就會被推入一個環境棧中,而函數執行之後,棧將其環境彈出,把控制權返回給之前的執行環境。作用域鏈由一個全局對象組成,。在不包含嵌套函數的函數體內,作用域鏈上有兩個對象,第一個是定義函數參數和局部變量的對象。第二個是全局對象。在一個嵌套的函數體內,作用域鏈上至少有三個對象。當定義一個函數時,它實際上保存一個作用域鏈。當調用這個函數時,它創建一個新的對象來儲存它的局部變量,並將這個對象添加至保存的那個作用域鏈上,同時創建一個新的更長的表示函數調用的作用域的“鏈”。函數對象可以通過作用域鏈關聯起來,函數體內部變量都可以保存在函數作用域內,這種特性成爲“閉包”。

理解閉包首先要了解嵌套函數的詞法作用域規則。看一下這段代碼
var scope = "global scope";
function checkscope() {

var scope = "local scope";
function f(){return scope;}
return f();

}
checkscope(); //"local scope"


我們對代碼做一點改動,將函數內的一對圓括號移動到了checkscope()之後。代碼如下

var scope = "global scope";
function checkscope() {

var scope = "local scope";
function f(){return scope;}
return f;

}
checkscope()(); //"local scope"

我們可以看到兩者執行的結果是一樣的,js函數執行用到了作用域鏈,這個作用域鏈是函數 定義的時候創建的。嵌套函數f()定義在這個作用域鏈裏,其中變量scope是局部變量,不管在何時何地執行函數f(),這種綁定在執行f()時依然有效。

閉包的實現,我們將作用域鏈描述爲一個對象列表,每次調用js函數的時候,都會爲之創建一個新的對象用來保存局部變量,把這個對象添加至作用域鏈中。當函數返回的時候,就從作用域鏈中將這個綁定變量的對象刪除。如果不存在嵌套函數,也沒有其他引用指向這個綁定的對象。它就會被當做垃圾回收掉。如果定義了 嵌套的函數,每個嵌套的函數都各自對應一個作用域鏈,並且這個作用域鏈指向一個變量綁定函數,但如果這些嵌套的函數在外部函數中保存了下來,那麼也會和所指向的變量綁定對象一樣當做垃圾回收,但如果這個函數定義了嵌套函數,並將它 作爲返回值返回或者存儲在某處的屬性裏,這時就會有一個外部引用指向這個嵌套函數。它就不會被當做垃圾回收,並且它所指向的變量 綁定對象也不會被當做 垃圾回收。


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