關於閉包的理解(JS學習小結)

前言:css

啊啊啊,看書真的很痛苦啊,仍是好想作項目寫代碼纔有意思,不過我如今缺的確是將知識體系化,因此不論看書多麼痛苦都必定要堅持堅持啊,這纔是我如今最須要的進步的地方,加油!前端

由於如今期末啦,下週一也就是明天開始就有考試,因此複習是主要的事情,看書的速度比較慢了,一週大概也就184頁(P110-P284), 雖然頁數比較少可是其中有ES中很是最重要的兩個概念——原型鏈閉包,以前對於兩個知識的瞭解算是知其然不知其因此然的,因此在那兩章我也有意多花費了時間,確保我可以吃透這個概念。如下算是我本身的一些理解,若是有不很正確的地方,但願大神們多多指教,康桑阿米達~編程

哦,對了,我看的JS書是《Javascript 高級程序設計(第3版)》,若是有正在看這本書的小夥伴能夠一塊兒哇~你們多多交流,互相學習嘛~閉包

 

正文:編程語言

如今最流行的編程語言裏面必定有「對象」的概念,咱們的第一節實驗課老師就叫咱們怎麼找對象,因此可見對象對於程序猿的重要性,因此你有對象了嘛?:) 那這世界上對象千千萬,咱們怎麼知道哪一個對象合適呢?總不能一個一個的相處試試看吧?好在咱們發現不少對象都有類似之處,因此咱們將他們類似的部分抽象出來,造成了一個全新的概念,在咱們須要的時候,比對咱們的須要和這個概念,再進行選擇,就會節省咱們不少功夫並更好更快的得到咱們想要的結果。而這個概念在JS中就是引用類型,Object(JS中沒有類的概念,若是學過C++或者Java、C#等語言的,那也會很容易就對應get到JS中引用類型的)。Object確實是JS中很是強大的部分,但卻不是最有意思的,那最有意思的是什麼?Function。函數

在JS中,Function也是一個Object的一個對象。而關於這個概念的延伸,像是繼承、原型鏈等等就又能夠再開一把了,若是實在是飢渴難耐的,那就快去搜索大神們博客或者找一本《JavaScript高級程序設計》和我一塊兒學習啦~因此,咱們如今就將矛頭對準,閉包!開火,嘣嘣嘣嘣學習

在說閉包的概念以前,咱們總得知道這個名詞究竟是什麼意思吧?spa

因此什麼是閉包?函數。設計

既然就是函數爲何又特別要取個名字?它到底特別在哪?code

可以訪問另外一個函數做用域中的變量。(此處的做用域姑且理解爲{}以內)

For example,上個例子就知道了,不要問我例子是誰

function outerFunc(arg){

   return function innerFunc(){
        alert(arg);
    }  

}

此處名爲outerFunc的函數返回了一個名爲innerFunc函數,這個函數在內部只有一句「alert(arg);」,但是運用技能一眼看穿法,找不到arg,再往上,哇哦,在outerFunc的參數那找到了呢,真開心。因此這個innerFunc(函數)訪問了outerFunc(另外一個函數)做用域內(在outerFunc的{}中,但沒在innerFunc的{}中)的變量(arg),因此這個innerFunc就是一個閉包。(大多數時候,不會爲閉包命名,此處只爲更好的說明。)

OK,閉包的概念知道啦,那如何造成閉包這個現象的呢?顯然剛剛別有深意,欲拒還迎的做用域使的小把戲啦,別怕,咱們立馬拿下。

「當某個函數被調用時,會建立一個執行環境及相應的做用域鏈。」

「每一個執行環境都有一個表示變量的對象——變量對象。(variable object)。」

固然仍是要先名詞解釋,要是都不知道這個名詞指的什麼,那還怎麼玩。

做用域:也就是變量對象的別稱。

做用域鏈:就是做用域唄。一條把做用域像臘肉穿起來的子。它只是一條鏈子因此做用域鏈就只保存着變量對象地址,而不是變量對象自己。

執行環境執行環境指向本身獨有的做用域鏈做用域鏈又按照當前函數做用域,外部函數做用域,外部函數的外部函數做用域....直至全局做用域。

再來了解了解,咱們寫了個函數而後調用它實現了功能,那JS到底又爲此作了什麼。
(1)在建立函數時,會建立一個預先包含全局變量對象的做用域鏈,保存在內部的屬性[[scope]]中。
(2)當調用函數時,會爲函數建立一個執行環境,而後經過複製函數的[[scope]]屬性,構建起執行環境的做用域鏈。
(3)建立一個活動對象(此處即變量對象)放在執行環境做用域鏈的最前端。
而當函數在訪問一個變量的時候,即在innerFunc函數的執行環境中執行到「alert(arg);」時,執行環境找到本身的做用域鏈小夥伴,而後做用域鏈說沒問題,我幫你問問個人做用域兄弟們,而後做用域鏈就問innerFunc()做用域,「你好,請問你有arg這個變量嗎?」「很差意思,我沒有呢。」「不要緊哦。謝謝你。」「不客氣。」(老師教導咱們要作一個有禮貌的好孩子。)而後它又問outerFunc()做用域,「請問你有arg這個變量嗎?」「我有哦。」ok,皆大歡喜,找到了arg,順利執行了「alert(arg);」語句,不然一直到全局做用域依然沒有找到的話,就只能報錯了呢。
通常講,函數執行完畢,那就銷燬吧。可是,閉包就這麼被銷燬了,哪裏對得起它特別的名字呢?
 1 function outerFunc(arg){
 2 
 3    return function innerFunc(){
 4         alert(arg);
 5     }  
 6 
 7 }
 8 
 9 var result = outerFunc(1); //返回innerFunc函數
10 result();                  //輸出1

 

仍是剛纔的函數,仍是原來的配方,再加點料,看看效果。

按照剛剛說的,outerFunc在第9行執行完畢後,應該就被銷燬了(事實上也是如此),但爲什麼第10行的執行依然可以成功呢?聰明的你必定知道啦,做用域和做用域鏈的關係。outerFunc在第9行執行後,outerFunc的執行環境和做用域鏈都被銷燬,可是!innerFunc的做用域鏈還在對innerFunc做用域和outerFunc做用域進行引用。也就是所謂了「引用計數不惟一」。因此,儘管outerFunc已經被銷燬,可是innerFunc依然可以訪問到arg變量的值啦。
因此你看閉包並無很難嘛,不用怕它,固然我在此說的,都是簡單的初級概念,閉包的運用就像是css中的浮動的運用同樣,知道概念是很容易的事情,可是真的運用駕輕就熟確實是很是高段位的事了,因此一塊兒加油咯~
 
後話:
明天考試英語,但願能考好啊,我要求不高,上90就行啊。(強行裝逼,沒必要理我)
相關文章
相關標籤/搜索