閉包

雖然JavaScript是一門完整的面向?qū)ο蟮木幊陶Z(yǔ)言,但這門語(yǔ)言同時(shí)也擁有許多函數(shù)式語(yǔ)言的特性.
函數(shù)是語(yǔ)言的鼻祖是LISP,JavaScript在設(shè)計(jì)之初參考了LISP兩大方言之一的Scheme,引入了Lambda表達(dá)式,閉包,高階函數(shù)等特性.使用這些特性,我們經(jīng)??梢杂靡恍╈`活而巧妙的方式來(lái)編寫(xiě)JavaScript代碼.

閉包

變量的作用域

在JavaScript中,函數(shù)可以用來(lái)創(chuàng)造函數(shù)作用域.此時(shí)的函數(shù)向一層半透明的玻璃,在函數(shù)里面可以看到外面的變量,而在函數(shù)外面則無(wú)法看到函數(shù)里面的變量.這是因?yàn)樵诤瘮?shù)搜索一個(gè)變量的時(shí)候,如果該函數(shù)沒(méi)有聲明這個(gè)變量,那么此次搜索的過(guò)程會(huì)隨著代碼執(zhí)行環(huán)境創(chuàng)建的作用域往外層逐層搜索,一直搜索到全局對(duì)象為止.變量的搜索是內(nèi)到外而非從外到內(nèi)的.

變量的生存周期

除了變量的作用域之外,另外一個(gè)跟閉包有關(guān)的概念是變量的生存周期.
對(duì)于全局變量來(lái)說(shuō),全局變量的生存周期當(dāng)然是永久的,除非我們主動(dòng)銷毀這個(gè)全局變量.
而對(duì)于在函數(shù)內(nèi)的var關(guān)鍵字聲明的局部變量來(lái)說(shuō),當(dāng)退出函數(shù)是,這些局部變量即失去了它們的價(jià)值,它們都會(huì)隨著函數(shù)調(diào)用的結(jié)束而被銷毀.
但當(dāng)退出函數(shù)后,局部變量a并沒(méi)有消失,而是似乎一直在某個(gè)地方存活著.這是因?yàn)楫?dāng)執(zhí)行var f = func();時(shí),f返回了一個(gè)匿名函數(shù)的引用,它可以訪問(wèn)到func()被調(diào)用時(shí)產(chǎn)生的環(huán)境,而局部變量a一直處在這個(gè)環(huán)境里.既然局部變量所在的環(huán)境還能被外界訪問(wèn),這個(gè)局部變量就有了不被銷毀的理由.在這里產(chǎn)生了一個(gè)閉包結(jié)構(gòu),局部變量的生命看起來(lái)被延續(xù)了.(函數(shù)的作用域在函數(shù)創(chuàng)建之初就已經(jīng)被確定,不會(huì)因?yàn)楸徽{(diào)用而改變!)

閉包和面向?qū)ο笤O(shè)計(jì)

過(guò)程與數(shù)據(jù)的結(jié)合是形容面向?qū)ο笾械?對(duì)象"時(shí)經(jīng)常使用的表達(dá).對(duì)象以方法的形式包含了過(guò)程,而閉包則是在過(guò)程中以環(huán)境的形式包含了數(shù)據(jù).通常用面向?qū)ο笏枷肽軐?shí)現(xiàn)的功能,用閉包也能實(shí)現(xiàn).反之亦然.

閉包與內(nèi)存管理

局部變量本來(lái)應(yīng)該在函數(shù)退出的時(shí)候解除引用,但如果局部變量被封閉在閉包形成的環(huán)境中,那么這個(gè)局部變量就能一直生存下去.從和這個(gè)意義上看,閉包的確會(huì)使一些數(shù)據(jù)無(wú)法被及時(shí)銷毀.使用閉包的一部分原因是我們選擇主動(dòng)把一些變量封閉在閉包中,因?yàn)榭赡茉谝院筮€需要使用這些變量,把這些變量放在閉包中和放在全局作用域,對(duì)內(nèi)存方面的影響是一致的,這里并不能說(shuō)成是內(nèi)存泄露,如果在將來(lái)需要回收這些變量,我們可以手動(dòng)把這些變量設(shè)為Null.
跟閉包和內(nèi)存泄露有關(guān)系的地方是,使用閉包的同時(shí)比較容易形成循環(huán)引用,如果閉包的作用域鏈中保存著一些DOM節(jié)點(diǎn),這時(shí)候就有可能造成內(nèi)存泄露,但這本身并非閉包的問(wèn)題,也并非JavScript的問(wèn)題,在IE瀏覽器中,由于 BOM和DOM中的對(duì)象是使用C++以COM對(duì)象的方式實(shí)現(xiàn)的,而COM對(duì)象的垃圾會(huì)師集機(jī)制采用的是引用計(jì)數(shù)策略.在基于引用計(jì)策略的垃圾回收機(jī)制中,如果兩者對(duì)象之間形成了循環(huán)引用,那么這兩個(gè)對(duì)象都無(wú)法被回收,但循環(huán)引用造成的內(nèi)存泄漏的本質(zhì)上也不是閉包造成的.
同樣,如果要解決循環(huán)引用帶來(lái)的內(nèi)存泄露問(wèn)題,我們需要把循環(huán)引用中的變量設(shè)為null即可.將變量設(shè)置為null意味著切斷變量與它此前引用的值之間的連接.當(dāng)垃圾收集器下次運(yùn)行時(shí),就會(huì)刪除這些值并回收它們占用的內(nèi)存.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容