閉包是一個比較抽象的概念,尤其是對js新手來說.書上的解釋實在是比較晦澀,對我來說也是一樣.
但是他也是js能力提升中無法繞過的一環(huán),幾乎每次面試必問的問題,因為在回答的時候.你的答案的深度,對術(shù)語的理解以及js內(nèi)部解釋器的運作方式的描述,都是可以看出你js實際水平的.即使你沒答對,也能讓考官對你的水平有個評估.那么我先來說說我對js中的閉包的理解.
閉包是很多語言都具備的特性,在js中,閉包主要涉及到j(luò)s的幾個其他的特性:作用域鏈,垃圾(內(nèi)存)回收機制,函數(shù)嵌套,等等.
在理解閉包以前.最好能先理解一下作用域鏈的含義,簡單來說,作用域鏈就是函數(shù)在定義的時候創(chuàng)建的,用于尋找使用到的變量的值的一個索引,而他內(nèi)部的規(guī)則是,把函數(shù)自身的本地變量放在最前面,把自身的父級函數(shù)中的變量放在其次,把再高一級函數(shù)中的變量放在更后面,以此類推直至全局對象為止.當(dāng)函數(shù)中需要查詢一個變量的值的時候,js解釋器會去作用域鏈去查找,從最前面的本地變量中先找,如果沒有找到對應(yīng)的變量,則到下一級的鏈上找,一旦找到了變量,則不再繼續(xù).如果找到最后也沒找到需要的變量,則解釋器返回undefined.
了解了作用域鏈,我們再來看看js的內(nèi)存回收機制,一般來說,一個函數(shù)在執(zhí)行開始的時候,會給其中定義的變量劃分內(nèi)存空間保存,以備后面的語句所用,等到函數(shù)執(zhí)行完畢返回了,這些變量就被認(rèn)為是無用的了.對應(yīng)的內(nèi)存空間也就被回收了.下次再執(zhí)行此函數(shù)的時候,所有的變量又回到最初的狀態(tài),重新賦值使用.但是如果這個函數(shù)內(nèi)部又嵌套了另一個函數(shù),而這個函數(shù)是有可能在外部被調(diào)用到的.并且這個內(nèi)部函數(shù)又使用了外部函數(shù)的某些變量的話.這種內(nèi)存回收機制就會出現(xiàn)問題.如果在外部函數(shù)返回后,又直接調(diào)用了內(nèi)部函數(shù),那么內(nèi)部函數(shù)就無法讀取到他所需要的外部函數(shù)中變量的值了.所以js解釋器在遇到函數(shù)定義的時候,會自動把函數(shù)和他可能使用的變量(包括本地變量和父級和祖先級函數(shù)的變量(自由變量))一起保存起來.也就是構(gòu)建一個閉包,這些變量將不會被內(nèi)存回收器所回收,只有當(dāng)內(nèi)部的函數(shù)不可能被調(diào)用以后(例如被刪除了,或者沒有了指針),才會銷毀這個閉包,而沒有任何一個閉包引用的變量才會被下一次內(nèi)存回收啟動時所回收.
也就是說,有了閉包,嵌套的函數(shù)結(jié)構(gòu)才可以運作,這也是符合我們的預(yù)期的.然后,閉包還有一些特性,卻往往讓程序員覺得很難理解.