web前端面試題js閉包理解_第1頁
web前端面試題js閉包理解_第2頁
免費(fèi)預(yù)覽已結(jié)束,剩余4頁可下載查看

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1、一、閉包?”的解釋是:閉包是一個(gè)擁有許多變量和綁定了這些變量的環(huán)境的表達(dá)式(通常是一個(gè)函數(shù)),因而這些變量也是該表達(dá)式的一部分。相信很少有人能直接看懂這句話,因?yàn)樗枋龅奶珜W(xué)術(shù)。其實(shí)這句話通俗的來說就是:JavaScript 中所有的 function 都是一個(gè)閉包。不過一般來說,嵌套的 function 所產(chǎn)生的閉包更為強(qiáng)大,也是大部分時(shí)候所謂的“閉包”??聪旅孢@段代碼:1 function a() 2 varvar c = a();7 c();i = 0; 3function b() alert(+i); 4return b;56這段代碼有兩個(gè)特點(diǎn):1、函數(shù) b 嵌套在函數(shù) a;2、函數(shù)

2、a 返回函數(shù)b。關(guān)系如圖:這樣在執(zhí)行完 var c=a()后,變量 c 實(shí)際上是指向了函數(shù)b,再執(zhí)行 c()后就會(huì)彈出一個(gè)窗口顯示 i 的值(第一次為 1)。這段代碼其實(shí)就創(chuàng)建了一個(gè)閉包,為什么?因?yàn)楹瘮?shù) a 外的變量 c了函數(shù)a 內(nèi)的函數(shù)b,就是說:當(dāng)函數(shù) a 的函數(shù) b 被函數(shù) a 外的一個(gè)變量的時(shí)候,就創(chuàng)建了一個(gè)閉包。讓說的更透徹一些。所謂“閉包”,就是在構(gòu)造函數(shù)體內(nèi)定義另外的函數(shù)作為目標(biāo)對象的方法函數(shù),而這個(gè)對象的方法函數(shù)反過來外層函數(shù)體中的臨時(shí)變量。這使得只要目標(biāo)對象在生存期內(nèi)始終能保持其方法,就能間接保持原構(gòu)造函數(shù)體當(dāng)時(shí)用到的臨時(shí)變量值。盡管最開始的構(gòu)造函數(shù)調(diào)用已經(jīng)結(jié)束,臨時(shí)變量的

3、名稱也都了,但在目 標(biāo)對象的方法。即使再次調(diào)用相同的構(gòu)造內(nèi)卻始終能到該變量的值,而且該值只能通這種方法來函數(shù),但只會(huì)生成新對象和方法,新的臨時(shí)變量只是對應(yīng)新的值,和上次那次調(diào)用的是各自獨(dú)立的。二、變量的作用域要理解閉包,首先必須理解 Javascript 特殊的變量作用域。變量的作用域無非就是兩種:全局變量和局部變量。Javascript 語言的特殊之處,就在于函數(shù)可以直接全局變量。下面通過一段代碼來看一下1 var n=999;2function f1()3alert(n);45f1(); / 999另一方面,在函數(shù)外部自然無法函數(shù)內(nèi)的局部變量。1 function f1()2var n=9

4、99;34alert(n); /error變量的時(shí)候,一定要使用 var 命令。如果不用的話,這里有一個(gè)地方需要注意,函數(shù)你實(shí)際上了一個(gè)全局變量!1 function f1()2n=999;34f1();5alert(n); / 999以上只是一個(gè)關(guān)于 javascript 變量作用域基礎(chǔ)的例子。三、如何從外部局部變量?(閉包)有時(shí)候需要得到函數(shù)內(nèi)的局部變量。但是,前面已經(jīng)不到的,只有通過變通方法才能實(shí)現(xiàn)。了,正常情況下,這是辦當(dāng)然這個(gè)變通的方法便是使用閉包,下面再通過一個(gè)例子來看一下1 function f1()2 alert(n);5/ 999n=999;3return f2;7funct

5、ion f2()468var result=f1();9result();這個(gè)便是閉包的一個(gè)簡單的例子。由于在 Javascript 語言中,只有函數(shù)的子函數(shù)才能局部變量,因此可以把閉包簡單理解成“定義在一個(gè)函數(shù)部連接起來的一座橋梁。的函數(shù)”。所以,在本質(zhì)上,閉包就是將函數(shù)和函數(shù)外和面有變量。象的語言相比,閉包便是使用對象中一個(gè)特定的公有函數(shù)去這個(gè)對象的私四、閉包的用途閉包可以用在許多地方。它的最大用處有兩個(gè),一個(gè)是前面提到的可以變量,另一個(gè)就是讓這些變量的值始終保持在內(nèi)存中。函數(shù)的怎么來理解這句話呢?請看下面的代碼。1 function f1()var n=999;nAdd=function

6、()n+=1function f2()alert(n);return f2;var result=f1();result(); / 999nAdd();result(); / 1000在這段代碼中,result 實(shí)際上就是閉包 f2 函數(shù)。它一共運(yùn)行了兩次,第一次的值是 999,第二次的值是 1000。這證明了,函數(shù) f1 中的局部變量 n 一直保存在內(nèi)存中,并沒有在 f1調(diào)用后被自動(dòng)清除。為什么會(huì)這樣呢?原因就在于 f1 是 f2 的父函數(shù),而 f2 被賦給了一個(gè)全局變量,這導(dǎo)致f2 始終在內(nèi)存中,而 f2 的存在依賴于 f1,因此 f1 也始終在內(nèi)存中,因?yàn)槿肿兞恐挥性诖a執(zhí)行完退出的時(shí)

7、候才清楚,所以 f1 不會(huì)在調(diào)用結(jié)束后,被collection)回收,而會(huì)一直存在直到程序退出?;厥諜C(jī)制(garbage這段代碼中另一個(gè)值得注意的地方,就是“nAdd=function()n+=1”這一行,首先在 nAdd前面沒有使用 var 關(guān)鍵字,因此 nAdd 是一個(gè)全局變量,而不是局部變量。其次,nAdd 的值是一個(gè)函數(shù)(anonymous function),而這個(gè)函數(shù)本身也是一個(gè)閉包,所以 nAdd相當(dāng)于是一個(gè) setter,可以在函數(shù)外部對函數(shù)的局部變量進(jìn)行操作。五、Javascript 的回收機(jī)制還是以這個(gè)圖來說:在 Javascript 中,如果一個(gè)對象不再被,那么這個(gè)對象就

8、會(huì)被 GC 回收。如果兩個(gè)對象互相數(shù) a 被b,而不再被第 3 者所,那么這兩個(gè)互相的對象也會(huì)被回收。因?yàn)楹?,b 又被a 外的 c,這就是為什么函數(shù) a 執(zhí)行后不會(huì)被回收的原因。六、使用閉包的1、由于閉包會(huì)使得函數(shù)中的變量都被保存在內(nèi)存中,內(nèi)存消耗很大,所以不能閉包,否則會(huì)造成網(wǎng)頁的性能問題,在 IE 中可能導(dǎo)致內(nèi)存前,將不使用的局部變量全部刪除。解決方法是,在退出函數(shù)之2、閉包會(huì)在父函數(shù)外部,改變父函數(shù)變量的值。所以,如果你把父函數(shù)當(dāng)作對象(object)使用,把閉包當(dāng)作它的公用方法(Public Method),把變量當(dāng)作它的私有屬變量的值。性(private value),這時(shí)一定要,不

9、要隨便改變父函數(shù)七、思考題如果你能理解下面代碼的運(yùn)行結(jié)果,應(yīng)該就算理解閉包的運(yùn)行機(jī)制了。1 var name = The Window;2var object = 53name : My Object,4getNameFunc : function()return function()6return ;7;89 ;10alert(object.getNameFunc()(); /The Window上面例子中對象中 getNameFunc 方法使用了一個(gè)閉包,而這個(gè)返回的閉包中又包含了一個(gè)閉包返回 ,當(dāng)執(zhí)行 object.getNameFunc()()時(shí),會(huì)

10、先到第一對圓括號(hào)執(zhí)行 getNameFunc 函數(shù),返回了一個(gè)閉包函數(shù),然后再次讀后面的圓括號(hào),將這個(gè)閉包返回的函數(shù)執(zhí)行,然后返回 ,這段代碼里面相當(dāng)于執(zhí)行了兩層閉包。1 function outerFun() 2 3 var a=0; 4 function innerFun() 5 6a+; 7alert(a); 8 9 return innerFun; /注意這里 10 11 var obj=outerFun();12 obj();/結(jié)果為 113 obj(); /結(jié)果為 214 var obj2=outerFun();15 obj2(); /結(jié)果為 116 obj2()

11、;/結(jié)果為 2上面的例子,當(dāng)包 ,因?yàn)槭窃诒煌獠亢瘮?shù)在定義它的作用域的外部被時(shí),就創(chuàng)建了該函數(shù)的閉是創(chuàng)建了一個(gè)閉包,所以當(dāng)被外部兩次的時(shí)候便會(huì)同時(shí)也創(chuàng)建兩個(gè)閉包,每個(gè)閉包各不。如果函數(shù)了位于外部函數(shù)的變量,當(dāng)外部函數(shù)調(diào)用完畢后,這些變量在內(nèi)存不會(huì)被,因?yàn)殚]包需要它們。八、閉包內(nèi)的微觀世界如果要更加深入的了解閉包以及函數(shù) a 和嵌套函數(shù) b 的關(guān)系,需要引入另外幾個(gè)概念:函數(shù)的執(zhí)行環(huán)境(excution context)、活動(dòng)對象(call object)、作用域(scope)、作用域鏈(scope chain)。以函數(shù) a 從定義到執(zhí)行的過程為例闡述這幾個(gè)概念。1.當(dāng)定義函數(shù)a 的時(shí)候,js

12、解釋器會(huì)將函數(shù) a 的作用域鏈(scope chain)設(shè)置為定義 a時(shí) a 所在的“環(huán)境”,如果a 是一個(gè)全局函數(shù),則scope chain 中只有 window 對象。當(dāng)執(zhí)行函數(shù)a 的時(shí)候,a 會(huì)進(jìn)入相應(yīng)的執(zhí)行環(huán)境(excution context)。在創(chuàng)建執(zhí)行環(huán)境的過程中,首先會(huì)為 a 添加一個(gè)scope 屬性,即a 的作用域,其值就為第 1 步中的scope chain。即 a.scope=a 的作用域鏈。然后執(zhí)行環(huán)境會(huì)創(chuàng)建一個(gè)活動(dòng)對象(call object)?;顒?dòng)對象也是一個(gè)擁有屬性的對2.3.4.象,但它不具有原型而且不能通過 JavaScript 代碼直接。創(chuàng)建完活動(dòng)對象后,把

13、活動(dòng)對象添加到 a 的作用域鏈的最頂端。此時(shí) a 的作用域鏈包含了兩個(gè)對象:a 的活動(dòng)對象和window 對象。下一步是在活動(dòng)對象上添加一個(gè) arguments 屬性,它保存著調(diào)用函數(shù) a 時(shí)所傳遞的參數(shù)。5.6.最后把所有函數(shù)a 的形參和的函數(shù)b 的也添加到 a 的活動(dòng)對象上。在這一步中,完成了函數(shù) b 的的定義,因此如同第 3 步,函數(shù) b 的作用域鏈被設(shè)置為 b 所被定義的環(huán)境,即a 的作用域。到此,整個(gè)函數(shù) a 從定義到執(zhí)行的步驟就完成了。此時(shí) a 返回函數(shù)b 的給 c,又函數(shù) b 的作用域鏈包含了對函數(shù)a 的活動(dòng)對象的,也就是說b 可以到a 中定義的所有變量和函數(shù)。函數(shù) b 被 c收。,函數(shù) b 又依賴函數(shù)a,因此函數(shù) a 在返回后不會(huì)被 GC 回當(dāng)函數(shù)b 執(zhí)行的時(shí)候亦會(huì)像以上步驟一樣。因此,執(zhí)行時(shí)b 的作用域鏈包含了 3 個(gè)對象:b 的活動(dòng)對象、a 的活動(dòng)對象和window 對象,如下圖所示:,當(dāng)在函數(shù)b 中一個(gè)變量的時(shí)候,搜索順序是:1.先搜索自身的活動(dòng)對象,如果存在

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論