閉包的作用
閉包簡(jiǎn)單來(lái)說(shuō)就是函數(shù)中的函數(shù)牛曹,也可以把它理解為一種現(xiàn)象渴杆,就是說(shuō)一個(gè)函數(shù)要訪問另外一個(gè)目標(biāo)函數(shù)內(nèi)部的變量崭捍,就要在目標(biāo)函數(shù)中再定義一個(gè)函數(shù)(以此來(lái)把作用域鏈往下延長(zhǎng)一段,目的就是為了利用js在找自由變量時(shí),會(huì)沿著作用域鏈一級(jí)一級(jí)往上找的特點(diǎn))泞遗,并將這個(gè)定義的函數(shù)return出來(lái),供外部使用倔监。在實(shí)際開發(fā)中直砂,閉包主要是用來(lái)封裝變量,收斂權(quán)限浩习。
例子
function isFirstLoad(){
var list=[];
return function(option){
if(list.indexOf(option)>=0){
console.log('已存在')
}else{
list.push(option);
console.log('首次傳入');
}
}
}
var ifl=isFirstLoad();
ifl("winter");
ifl("dongodng");
ifl("winter");
可以看到訪問內(nèi)部函數(shù)的變量只能通過(guò)定義的isFirstLoad來(lái)訪問静暂,閉包的好處就是引用的作用域不會(huì)被方式做垃圾回收處理,當(dāng)然不合理的使用會(huì)很耗費(fèi)內(nèi)存谱秽。
作用域洽蛀、作用域鏈、調(diào)用對(duì)象
詞法作用域是函數(shù)定義時(shí)的作用域疟赊,即靜態(tài)作用域郊供。當(dāng)一個(gè)函數(shù)定義時(shí),他的詞法作用域就確定了近哟,詞法作用域說(shuō)明的是在函數(shù)結(jié)構(gòu)的嵌套關(guān)系下驮审,函數(shù)作用的范圍。這個(gè)時(shí)候也就形成了該函數(shù)的作用域鏈吉执。作用域鏈就是把這些具有嵌套層級(jí)關(guān)系的作用域串聯(lián)起來(lái)疯淫。函數(shù)的內(nèi)部[[scope]]屬性指向了該作用域鏈。
動(dòng)態(tài)作用域是函數(shù)調(diào)用執(zhí)行時(shí)的作用域戳玫。當(dāng)一個(gè)函數(shù)被調(diào)用時(shí)熙掺,首先將函數(shù)內(nèi)部[[scope]]屬性指向了函數(shù)的作用域鏈,然后會(huì)創(chuàng)建一個(gè)調(diào)用對(duì)象咕宿,并用該調(diào)用對(duì)象記錄函數(shù)參數(shù)和函數(shù)的局部變量适掰,將其置于作用域鏈頂部。動(dòng)態(tài)作用域就是通過(guò)把該調(diào)用對(duì)象加到作用域鏈的頂部來(lái)創(chuàng)建的荠列,此時(shí)的[[scope]]除了具有定義時(shí)的作用域鏈类浪,還具有了調(diào)用時(shí)創(chuàng)建的調(diào)用對(duì)象。換句話說(shuō)肌似,執(zhí)行環(huán)境下的作用域等于該函數(shù)定義時(shí)就確定的作用域鏈加上該函數(shù)剛剛創(chuàng)建的調(diào)用對(duì)象费就,從而也形成了新的作用域鏈。所以說(shuō)是動(dòng)態(tài)的作用域川队,并且作用域鏈也隨之發(fā)生了變化力细。再看這里的作用域,其實(shí)是一個(gè)對(duì)象鏈固额,這些對(duì)象就是函數(shù)調(diào)用時(shí)創(chuàng)建的調(diào)用對(duì)象眠蚂,以及他上面一層層的調(diào)用對(duì)象直到最上層的全局對(duì)象《孵铮
譬如全局環(huán)境下的函數(shù)A內(nèi)嵌套了一個(gè)函數(shù)B逝慧,則該函數(shù)B的作用域鏈就是:函數(shù)B的作用域—>函數(shù)A的作用域—>全局window的作用域。當(dāng)函數(shù)B調(diào)用時(shí),尋找某標(biāo)識(shí)符笛臣,會(huì)按函數(shù)B的作用域—>函數(shù)A的作用域—>全局window的作用域去尋找云稚,實(shí)際上是按函數(shù)B的調(diào)用對(duì)象—>函數(shù)A的調(diào)用對(duì)象—>全局對(duì)象這個(gè)順序去尋找的。也就是說(shuō)當(dāng)函數(shù)調(diào)用時(shí)沈堡,函數(shù)的作用域鏈實(shí)際上是調(diào)用對(duì)象鏈静陈。
延長(zhǎng)變量的壽命
除了變量的作用域,另外一個(gè)和閉包有著親密關(guān)系的就是變量的生存周期了诞丽。一般來(lái)說(shuō)鲸拥,全局變量的生存周期是永久的,直到我們主動(dòng)銷毀僧免。而在函數(shù)內(nèi)不用var關(guān)鍵字聲明的局部變量來(lái)說(shuō)刑赶,當(dāng)退出函數(shù)時(shí),這些函數(shù)變量立即失去它們的價(jià)值猬膨,也就被垃圾回收機(jī)制銷毀了角撞,也算壽終正寢〔眨可是在閉包中谒所,卻不是這樣。
var a = 1;
a++;
console.log(a);
};
func();
func();
func();
可以看到a變量在函數(shù)結(jié)束的時(shí)候就已經(jīng)被銷毀了沛申。
var a = 1;
return function(){ //匿名函數(shù)
a++;
console.log(a);
}
};
var f = func();
f();
f();
f();
f();
可以看到閉包中的變量在函數(shù)結(jié)束的時(shí)候依然存在劣领,保存在內(nèi)存中,可以繼續(xù)訪問到铁材,這就實(shí)現(xiàn)了變量的分裝和復(fù)用尖淘。