千鋒教育JavaScript全套視頻教程(10天學(xué)會(huì)Js,前端javascrip

閉包(closure)是一個(gè)函數(shù)以及其捆綁的周邊環(huán)境狀態(tài)(lexical environment,詞法環(huán)境)的引用的組合。換而言之就是可以讓內(nèi)部函數(shù)訪(fǎng)問(wèn)到外部函數(shù)的作用,閉包會(huì)隨著函數(shù)的創(chuàng)建而被同時(shí)創(chuàng)建。
?我們來(lái)創(chuàng)建一個(gè)簡(jiǎn)單的閉包。
?????function fn(){
??????let?i = 0;
??????return function(){
????????i++;
????????return i;
??????}
????}
????let isSum = fn();
????console.log(isSum());
????console.log(isSum());
????console.log(isSum());
????console.log(isSum());
?我們可以看到我們?cè)L問(wèn)的是內(nèi)部函數(shù),但是卻用到了外部函數(shù)中的變量,而且我們發(fā)現(xiàn)我們每一次的調(diào)用實(shí)際過(guò)程中外部變量并沒(méi)有從新定義而是像全局變量一樣做到了常駐。為什么會(huì)這樣的效果呢?這就運(yùn)用到了閉包的兩個(gè)基本原理:垃圾回收機(jī)制、作用域鏈。
垃圾回收機(jī)制、作用域鏈
垃圾回收機(jī)制可分為兩種方式分別是:引用計(jì)數(shù)法、標(biāo)記清除法。
引用計(jì)數(shù)法:這種方式常常會(huì)引起內(nèi)存泄漏,低版本的IE使用這種方式。機(jī)制就是跟蹤一個(gè)值的引用次數(shù),當(dāng)聲明一個(gè)變量并將一個(gè)引用類(lèi)型賦值給該變量時(shí)該值引用次數(shù)加1,當(dāng)這個(gè)變量指向其他一個(gè)時(shí)該值的引用次數(shù)便減一。當(dāng)該值引用次數(shù)為0時(shí),則說(shuō)明沒(méi)有辦法再訪(fǎng)問(wèn)這個(gè)值了,被視為準(zhǔn)備回收的對(duì)象,每當(dāng)過(guò)一段時(shí)間開(kāi)始垃圾回收的時(shí)候,就把被引用數(shù)為0的變量回收。引用計(jì)數(shù)方法可能導(dǎo)致循環(huán)引用,類(lèi)似死鎖,導(dǎo)致內(nèi)存泄露。
標(biāo)記清除:JavaScript中常用的清除機(jī)制
(1)當(dāng)變量進(jìn)入執(zhí)行環(huán)境時(shí)(函數(shù)中聲明變量),就標(biāo)記這個(gè)變量為“進(jìn)入環(huán)境”,當(dāng)變量離開(kāi)環(huán)境時(shí)(函數(shù)執(zhí)行結(jié)束),則將其標(biāo)記為“離開(kāi)環(huán)境”,離開(kāi)環(huán)境之后還有的變量則是需要被刪除的變量。
(2)垃圾回收器在運(yùn)行的時(shí)候會(huì)給存儲(chǔ)在內(nèi)存中的所有變量都加上標(biāo)記。
(3)去掉環(huán)境中的變量以及被環(huán)境中變量引用的變量的標(biāo)記。
(4)之后再被加上標(biāo)記的變量即是需要回收的變量(因?yàn)榄h(huán)境中的變量已經(jīng)無(wú)法訪(fǎng)問(wèn)到這些變量)
(5)最后,垃圾收集器完成內(nèi)存清除工作,銷(xiāo)毀那些帶標(biāo)記的值,并回收他們所占用的內(nèi)存空間。
作用域鏈
各個(gè)作用域的嵌套關(guān)系組成一條作用域鏈。例子中 內(nèi)部函數(shù)的作用域鏈?zhǔn)?本身 -> fn -> 全局, fn函數(shù)保存在作用域鏈?zhǔn)?fn -> 全局
作用域鏈主要是進(jìn)行標(biāo)識(shí)符(變量和函數(shù))的查詢(xún),標(biāo)識(shí)符解析就是沿著作用域鏈一級(jí)一級(jí)的搜索標(biāo)識(shí)符的過(guò)程,而作用域鏈就是保證對(duì)變量和函數(shù)的有序訪(fǎng)問(wèn)。
閉包的優(yōu)點(diǎn)
可以減少全局變量的定義,避免全局變量的污染
能夠讀取函數(shù)內(nèi)部的變量
在內(nèi)存中維護(hù)一個(gè)變量,可以用做緩存
閉包的缺點(diǎn)
造成內(nèi)存泄露 :閉包會(huì)使函數(shù)中的變量一直保存在內(nèi)存中,內(nèi)存消耗很大,所以不能濫用閉包,否則會(huì)造成網(wǎng)頁(yè)的性能問(wèn)題,在IE中可能導(dǎo)致內(nèi)存泄露。解決方法——使用完變量后,手動(dòng)將它賦值為null;
閉包可能在父函數(shù)外部,改變父函數(shù)內(nèi)部變量的值。