資源描述:
《javascript閉包真經(jīng)》由會(huì)員上傳分享,免費(fèi)在線閱讀,更多相關(guān)內(nèi)容在應(yīng)用文檔-天天文庫(kù)。
1、Javascript閉包真經(jīng)繼前陣子寫完對(duì)象真經(jīng)后,這篇文章我嘗試盡力的去講透Js中的閉包。這里要感謝愛民,愛民的書寫得很好,我從中獲益良多。不過這次我打算換一種思路來寫這篇真經(jīng),就是采用提問回答的方式,我下面先提出我要回答的問題,如果讀者你都很自信的能夠回答上,那么就可以考慮干別的事情去了。如果感覺自己有點(diǎn)把握不準(zhǔn)就請(qǐng)給我一步步的尋址吧。:)我保證最后你就會(huì)豁然開朗,明白閉包的真諦。問題集:什么是函數(shù)實(shí)例?什么是函數(shù)引用?什么是閉包?閉包里有什么玩意?函數(shù)實(shí)例、函數(shù)引用和閉包有什么聯(lián)系?閉包的產(chǎn)
2、生的情形?閉包中的標(biāo)識(shí)符的優(yōu)先級(jí)是什么樣的?閉包帶來的可見性問題。什么是函數(shù)實(shí)例呢?其實(shí)在我們平常書寫代碼的過程中,寫的函數(shù)就是一段文本,只是對(duì)于編譯型語言來說會(huì)把它編譯為確定的二進(jìn)制代碼,并放到確定的內(nèi)存位置執(zhí)行,而對(duì)于Js這樣的解釋型語言,就會(huì)在程序運(yùn)行的時(shí)候把這段文本翻譯為計(jì)算機(jī)能懂的話。那么這里函數(shù)代碼的文本其實(shí)就是這個(gè)函數(shù)的類,而Js引擎解釋后的內(nèi)存中的數(shù)據(jù)就是這個(gè)函數(shù)的實(shí)例了。所以函數(shù)的實(shí)例就是Js引擎讀過這段代碼后在內(nèi)存中產(chǎn)生的一段數(shù)據(jù)。什么是函數(shù)引用呢?函數(shù)引用就是指向剛才所說的那
3、段內(nèi)存數(shù)據(jù)的指針。也就是指向某個(gè)函數(shù)實(shí)例的指針。同一份實(shí)例可以有多個(gè)引用,只要該實(shí)例還有指向它的引用,占用的內(nèi)存就不會(huì)被釋放。什么是閉包呢?閉包就是函數(shù)實(shí)例執(zhí)行過程中動(dòng)態(tài)產(chǎn)生的一塊新的內(nèi)存里的數(shù)據(jù)集。這句話有可以表達(dá)兩層意思:最初閉包必須由函數(shù)實(shí)例被調(diào)用(也就是函數(shù)實(shí)例執(zhí)行)時(shí)才會(huì)由Js引擎動(dòng)態(tài)生成;既然閉包也是一段內(nèi)存區(qū)域,當(dāng)沒有依賴于這個(gè)內(nèi)存中數(shù)據(jù)的引用時(shí),才會(huì)被釋放,也就是閉包理論上才會(huì)被銷毀。記住:閉包是執(zhí)行期的概念!那閉包里有什么玩意呢?這里我要引入Js引擎在語法分析期就構(gòu)造的兩類結(jié)構(gòu)。
4、執(zhí)行上下文結(jié)構(gòu)(Context)和調(diào)用對(duì)象結(jié)構(gòu)(CallObject)。我們還是先看一幅圖片:從上面的圖片我們?nèi)菀卓闯?,這是描述一個(gè)函數(shù)實(shí)例信息的圖。Context結(jié)構(gòu)包含了myFunc函數(shù)的類型(FUNCTION)、名稱(myFunc)、形式參數(shù)(x,y,z)和最關(guān)鍵的CallObject結(jié)構(gòu)的引用(body為CallObject)。而CallObject結(jié)構(gòu)就是很詳細(xì)的記錄了這個(gè)函數(shù)的全部語法分析結(jié)構(gòu):內(nèi)部聲明的變量表(localDeclVars)、內(nèi)部聲明的具名函數(shù)表(localDeclFu
5、ncs)以及除去以上內(nèi)容之外的其它所有代碼文本的字符串表示(source)。好,現(xiàn)在有了這個(gè)語法分析期就產(chǎn)生的CallObject結(jié)構(gòu),就好分析閉包里面會(huì)有什么了。當(dāng)一個(gè)函數(shù)實(shí)例被調(diào)用時(shí),實(shí)際上是從這個(gè)原型復(fù)制了一份CallObject結(jié)構(gòu)到閉包那塊空的內(nèi)存中去。同時(shí)會(huì)給里面的數(shù)據(jù)賦值。這里有兩個(gè)規(guī)則,大家要記下:在函數(shù)實(shí)例開始執(zhí)行時(shí),localDeclVars中的所有值將被置為undefined;在函數(shù)實(shí)例執(zhí)行結(jié)束并退出時(shí),localDeclVars不被重置,這就是Js中函數(shù)能夠在內(nèi)部保存數(shù)據(jù)的
6、特性的原因;這個(gè)閉包中的CallObject結(jié)構(gòu)中的數(shù)據(jù)能保留多久取決于是否還有對(duì)其的引用存在,所以這里就引出了一個(gè)推論,閉包的生存周期不依賴于函數(shù)實(shí)例。那么對(duì)于全局對(duì)象呢?是什么樣的結(jié)構(gòu)呢?其實(shí)和上面的函數(shù)實(shí)例的基本一樣,唯一不同的是,沒有Context,因?yàn)樗谧铐攲恿?。全局?duì)象里面也有一個(gè)CallObject,只是這個(gè)CallObject有點(diǎn)特殊,就是localDeclVars里面的數(shù)據(jù)只會(huì)初始化一次,且整個(gè)CallObject里的數(shù)據(jù)總不被銷毀。除了我講的復(fù)制了一份CallObject,再
7、往里賦值,閉包其實(shí)還包括了一個(gè)upvalue數(shù)組,這里數(shù)組里裝載的是閉包鏈上一級(jí)閉包中的標(biāo)識(shí)符(localDeclVars和localDeclFuncs及它自身的upvalue數(shù)組)的引用函數(shù)實(shí)例、函數(shù)引用和閉包有什么聯(lián)系呢?要回答這樣的問題,就要好好分別理解上面說的這個(gè)三個(gè)分別指的是什么。然后我想在回答這個(gè)問題前,通過代碼來感知一些東西。其實(shí)有時(shí)候人的思維需要一個(gè)載體去依靠,也就是我們常說的實(shí)踐才能出真知。[javascript]functionmyFunc(){this.doFunc=func
8、tion(){}}varobj={};//進(jìn)入myFunc,取得doFunc()的一個(gè)實(shí)例myFunc.call(obj);//套取函數(shù)實(shí)例的一個(gè)引用并賦值給funcvarfunc=obj.doFunc;//再次進(jìn)入myFunc,又取得了doFunc()的一個(gè)新實(shí)例myFunc.call(obj);//比較兩次取得的函數(shù)實(shí)例,結(jié)果顯示false,表明是不同的實(shí)例print(func===obj.doFunc);//顯示false//顯示true,表明兩個(gè)函數(shù)實(shí)例的代碼文本完全一樣p