一幅狮、定義
JS的閉包指的是具有這樣特征的一類函數(shù):
它能夠訪問(wèn)到其他函數(shù)作用域內(nèi)的局部變量
這里舉一個(gè)簡(jiǎn)單的例子來(lái)說(shuō)明:
首先需要理解的是 JS 的變量作用域——在函數(shù)內(nèi)可以直接訪問(wèn)函數(shù)外的全局變量;
var n=999;
function f1(){
alert(n);
}
f1(); // 999
而在函數(shù)外卻不能直接訪問(wèn)函數(shù)內(nèi)的局部變量。
function f1(){
var n=999;
}
alert(n); // error
而有時(shí)我們需要讀取函數(shù)內(nèi)的變量,這時(shí)我們就需要利用閉包皆看。
前面提到過(guò)在 JS 中由于鏈?zhǔn)阶饔糜蚪Y(jié)構(gòu)的存在鼎兽,子對(duì)象可以一級(jí)一級(jí)的向上訪問(wèn)到父對(duì)象的變量夜郁,即父對(duì)象的變量對(duì)子對(duì)象都是可見(jiàn)的儒将,而反之則不成立(類似 Java中內(nèi)部類與外部類的關(guān)系)。那么我們只要在函數(shù)內(nèi)再嵌套一個(gè)函數(shù)并把內(nèi)部函數(shù)作為外部函數(shù)的返回值捺宗,不就可以獲取到外部函數(shù)內(nèi)的局部變量了嗎柱蟀。
function f1(){
var n=999;
function f2(){
alert(n);
}
return f2;
}
var result=f1();
result(); // 999
這里我們就實(shí)現(xiàn)了一個(gè)閉包,不過(guò)從網(wǎng)上看到的有把result
叫閉包的蚜厉,也有把f2
叫閉包的长已,我個(gè)人認(rèn)為應(yīng)該f2
才是按照定義上的閉包,不過(guò)也不用對(duì)這個(gè)太糾結(jié)昼牛,知道閉包是干什么的就行了术瓮。
二、閉包的用法
閉包有一個(gè)與一般函數(shù)不同的特性:一般函數(shù)執(zhí)行完時(shí)贰健,其局部變量就被銷毀胞四,內(nèi)存中僅保存全局作用域;而閉包中的局部變量卻還可以保存在內(nèi)存中(類似靜態(tài)變量)伶椿。
這個(gè)特性既帶來(lái)了優(yōu)點(diǎn)撬讽,也帶來(lái)了潛在的問(wèn)題:
優(yōu)點(diǎn)
可以避免使用全局變量,從而避免過(guò)多全局變量造成的污染悬垃;
也方便了我們把一個(gè)局部變量駐留更久
缺點(diǎn)
如果不及時(shí)將對(duì)象引用釋放,則會(huì)造成內(nèi)存泄露甘苍;
閉包本身由于函數(shù)嵌套尝蠕,會(huì)對(duì)性能帶來(lái)一定的負(fù)面影響
這里舉兩個(gè)例子來(lái)說(shuō)明閉包的用法:
1、局部變量的累加
function outer(){
var x=10;
return function(){ //函數(shù)嵌套函數(shù)
x++;
alert(x);
}
}
var y = outer(); //外部函數(shù)賦給變量y;
y(); //y函數(shù)調(diào)用一次载庭,結(jié)果為11看彼,相當(dāng)于outer()
y(); //y函數(shù)調(diào)用第二次,結(jié)果為12囚聚,實(shí)現(xiàn)了累加
2靖榕、實(shí)現(xiàn)私用變量
JS 中并不像 Java 一樣有 Public、Private 等訪問(wèn)控制關(guān)鍵字顽铸,但我們可以用閉包來(lái)模擬這個(gè)特性:
var Counter = (function() {
var privateCounter = 0;
function changeBy(val) {
privateCounter += val;
}
return {
increment: function() {
changeBy(1);
},
decrement: function() {
changeBy(-1);
},
value: function() {
return privateCounter;
}
}
})();
alert(Counter.value()); // 提示 0
Counter.increment();
Counter.increment();
alert(Counter.value()); // 提示 2
Counter.decrement();
alert(Counter.value()); // 提示 1
這里privateCounter就變成了一個(gè)只能通過(guò)預(yù)先寫好的函數(shù)來(lái)控制與訪問(wèn)的私有變量茁计,等于實(shí)現(xiàn)了一種封裝。