昨天晚上上了網(wǎng)易前端微專業(yè)的第一次直播課,感覺非常好祷愉,老師也普及了一個(gè)之前面試經(jīng)常會(huì)被問到的問題——閉包窗宦。并且老師在一開始提出了一個(gè)近乎顛覆之前認(rèn)知的一個(gè)結(jié)論:閉包不會(huì)造成內(nèi)存泄漏。
相信這個(gè)結(jié)論也顛覆了很多人的一個(gè)認(rèn)知二鳄,那么我們接下來就來看看網(wǎng)易的老師是怎么解釋這個(gè)問題的吧赴涵。
閉包的概念最早出現(xiàn)于60年代订讼,最早實(shí)現(xiàn)閉包的程序語言是[Scheme]鳖敷。之后定踱,閉包被廣泛使用于[函數(shù)式編程]。
實(shí)際上至扰,閉包是一種帶有執(zhí)行環(huán)境的函數(shù)。執(zhí)行環(huán)境包括了:函數(shù)的詞法環(huán)境(this直秆、作用域)、標(biāo)識(shí)符列表(用到但是未聲明的變量)、表達(dá)式部分(函數(shù)體)粤剧。
下面舉一個(gè)JS中閉包的例子:
function fn(){
var a = 2;
return function (){
console.log(a) //2;
}
}
fn()();
在上面的例子中我們可以看到焕议,在內(nèi)部函數(shù)中,我們并沒有聲明變量a别瞭,可是輸出結(jié)果卻是2。這個(gè)a就屬于用到但未聲明的變量浸遗,這也就是閉包與一般函數(shù)最大的區(qū)別所在。
那么閉包到底會(huì)不會(huì)造成內(nèi)存泄漏呢?
我們先來看維基百科里對(duì)于內(nèi)存泄漏的定義:
在計(jì)算機(jī)科學(xué)中郑藏,內(nèi)存泄漏指由于疏忽或錯(cuò)誤造成程序未能釋放已經(jīng)不再使用的內(nèi)存。內(nèi)存泄漏并非指內(nèi)存在物理上的消失歌粥,而是應(yīng)用程序分配某段內(nèi)存后,由于設(shè)計(jì)錯(cuò)誤嬉探,導(dǎo)致在釋放該段內(nèi)存之前就失去了對(duì)該段內(nèi)存的控制,從而造成了內(nèi)存的浪費(fèi)定躏。
上面這段定義用通俗點(diǎn)的方法講就是:內(nèi)存泄漏就是一些可以避免的內(nèi)存花銷氏捞。
那么我們?cè)倩剡^頭看上面的例子,變量a是有實(shí)際用途的滞造,因此這樣的內(nèi)存開銷是不可避免的,因此這樣的形式并不叫內(nèi)存泄漏。
那么是什么原因會(huì)造成閉包會(huì)出現(xiàn)內(nèi)存泄漏這種說法的呢始绍?下面這張圖給出了答案:
由于IE的垃圾回收機(jī)制采用的是引用計(jì)數(shù)策略径簿,所以才會(huì)有閉包會(huì)造成內(nèi)存泄漏的說法。
引用計(jì)數(shù)是計(jì)算機(jī)編程語言中的一種內(nèi)存管理技術(shù),是指將資源(可以是對(duì)象柔昼、內(nèi)存或磁盤空間等等)的被引用次數(shù)保存起來碴萧,當(dāng)被引用次數(shù)變?yōu)榱銜r(shí)就將其釋放的過程虎谢。
而諸如Chrome擎场、Firefox等現(xiàn)代瀏覽器的垃圾回收機(jī)制是標(biāo)記清除式的垃圾回收算法礼饱。
標(biāo)記清除:垃圾收集器在運(yùn)行的時(shí)候會(huì)給存儲(chǔ)在內(nèi)存中的所有變量都加上標(biāo)記洒忧,然后榄鉴,它會(huì)去掉環(huán)境中的變量的標(biāo)記和被環(huán)境中的變量引用的變量的標(biāo)記,此后,如果變量再被標(biāo)記則表示此變量準(zhǔn)備被刪除。
至此我們應(yīng)該已經(jīng)明白了,JS中內(nèi)存泄漏的真正的罪魁禍?zhǔn)祝怖斫饬碎]包和內(nèi)存泄漏的概念。希望下次再被問到閉包相關(guān)的問題的時(shí)候,我們不再不知所措。
參考資料: