想要理解閉包满力,首先要知道變量作用域的概念焕参。
變量作用域
變量的作用域有兩種:全局變量和局部變量。
JS語(yǔ)言定義了:函數(shù)內(nèi)部可以直接讀取全局變量油额,但是函數(shù)外部無(wú)法讀取函數(shù)內(nèi)部的局部變量叠纷。
注意點(diǎn):
大家都知道,變量是需要用var關(guān)鍵字聲明的潦嘶。但是javascript中也可以隱式的使用變量涩嚣,就是不用聲明,直接使用掂僵。而且航厚,千萬(wàn)注意,javascript把隱式聲明的變量總是當(dāng)成全局變量來(lái)使用的锰蓬。
沒(méi)有var幔睬,let聲明的變量或者在函數(shù)外部聲明的變量都是全局變量;使用 var 聲明的變量屬于所在函數(shù)芹扭,不管在函數(shù)的哪個(gè)位置出現(xiàn)麻顶,等價(jià)于在函數(shù)一開(kāi)始聲明赦抖。該變量為局部變量,局部變量比同名全局變量的優(yōu)先級(jí)高辅肾。如何從外部讀到函數(shù)內(nèi)部的局部變量队萤?
某些情況下,需要從外部獲取函數(shù)內(nèi)部的局部變量矫钓,但是上面已經(jīng)提到要尔,正常情況下,是不允許訪問(wèn)的新娜,需要通過(guò)一定的方法才能實(shí)現(xiàn)
那就是赵辕,在函數(shù)內(nèi)部,在定義一個(gè)函數(shù)
function goPlat(){
var t=888;//局部變量
function showNumber(){
console.log(t);
}
return showNumber
}
this.result=goPlat();
this.result();//888
在上面的代碼中杯活,函數(shù)goPlat內(nèi)部的變量對(duì)函數(shù)showNumber都是可見(jiàn)的
反之匆帚,函數(shù)showNumber里面的變量對(duì)函數(shù)goPlat就是不可見(jiàn)的
這就是JS中的鏈?zhǔn)阶饔糜蚪Y(jié)構(gòu),子對(duì)象會(huì)向上一級(jí)一級(jí)尋找父對(duì)象的變量
所以父對(duì)象的變量對(duì)于子對(duì)象來(lái)說(shuō)都是可見(jiàn)的
所以旁钧,竟然函數(shù)showNumber可以讀取函數(shù)goPlat里面的t,那么把函數(shù)showNumber作為返回值互拾,不就可以在外部訪問(wèn)局部變量t了歪今。
閉包的概念
在上面的代碼中,函數(shù)showNumber就是一個(gè)閉包颜矿,閉包就是能夠讀取其他函數(shù)內(nèi)部變量的函數(shù)寄猩。
由于在JS中,只有函數(shù)內(nèi)部的子函數(shù)才能讀取局部變量骑疆,所以閉包也可以理解為:定義在一個(gè)函數(shù)內(nèi)部的函數(shù)田篇。
所以本質(zhì)上:閉包是連接函數(shù)內(nèi)部和函數(shù)外部的橋梁。閉包的用途
閉包最大的兩個(gè)用途:使得外部能夠訪問(wèn)函數(shù)內(nèi)部的變量箍铭;第二個(gè)就是讓這些變量的值始終保存在內(nèi)存中泊柬,不會(huì)在goPlat()調(diào)用后被清除。使用閉包的注意點(diǎn)
由于閉包會(huì)使得函數(shù)內(nèi)部的變量保存在內(nèi)存中诈火,內(nèi)存消耗很大兽赁,不能濫用閉包,否則會(huì)引起網(wǎng)頁(yè)性能問(wèn)題冷守,在IE中導(dǎo)致內(nèi)存泄漏刀崖,解決方法時(shí):在退出函數(shù)之前,將不使用的局部變量刪除拍摇。
閉包會(huì)在父函數(shù)外部改變父函數(shù)內(nèi)部局部變量的值亮钦,所以如果你把父函數(shù)當(dāng)做對(duì)象使用,把閉包當(dāng)成公共的方法充活,把內(nèi)部變量當(dāng)成私有屬性蜂莉,這時(shí)一定要小心蜡娶,不要隨意改變父函數(shù)內(nèi)部變量的值。