閉包是什么
保留局部變量不被釋放的代碼塊,稱為一個(gè)閉包
在js中,變量的作用域?qū)儆诤瘮?shù)的作用域,由于函數(shù)在執(zhí)行完畢后就會(huì)被清理,內(nèi)存也會(huì)被回收,但是由于閉包是建立在函數(shù)內(nèi)的子函數(shù),其可以訪問(wèn)上級(jí)作用域的原因,即使上級(jí)函數(shù)執(zhí)行完,作用域也不會(huì)隨之銷毀,這時(shí)的子函數(shù),便擁有了訪問(wèn)上級(jí)作用域中的變量的權(quán)限,即使上級(jí)函數(shù)執(zhí)行完后作用域內(nèi)的值也不會(huì)隨之銷毀。
閉包的作用
知道了閉包是什么,那么閉包到底能做些什么呢?
關(guān)于閉包,阮一峰這樣說(shuō)道:閉包就是能夠讀取其他函數(shù)內(nèi)部變量的函數(shù)。在Javascript語(yǔ)言中,只有函數(shù)內(nèi)部的子函數(shù)才能讀取局部變量,可以把閉包簡(jiǎn)單的理解成“定義在一個(gè)函數(shù)內(nèi)部的函數(shù)”。
本質(zhì)上,閉包就是將函數(shù)內(nèi)部和函數(shù)外部連接起來(lái)的一座橋梁。
來(lái)看一個(gè)例子:
function f(){
let a = 999;
function printNum() {
console.log(a);
}
return printNum
}
let a = f();
a()// 999
上面這個(gè)例子反映出了閉包的一個(gè)作用:可以訪問(wèn)函數(shù)內(nèi)的變量。
在js中,函數(shù)就相當(dāng)于一個(gè)黑盒子,從外界無(wú)法訪問(wèn)函數(shù)內(nèi)部的變量,但通過(guò)閉包就可以實(shí)現(xiàn)這樣的操作。
上面的代碼就形成了一個(gè)閉包,在函數(shù)f內(nèi)定義了一個(gè)變量a和一個(gè)函數(shù)printNum,printNum函數(shù)引用了函數(shù)f中定義的a,f函數(shù)又將printNum函數(shù)return了出去,這樣在函數(shù)外部也可以訪問(wèn)到f函數(shù)內(nèi)的a變量,由于printNum函數(shù)保持著對(duì)a的引用,因此a這個(gè)變量不會(huì)被銷毀。
通過(guò)以上的例子,我們可以總結(jié)出閉包的一些特點(diǎn):
1.持久化函數(shù)內(nèi)的變量
2.將函數(shù)內(nèi)部與外部連接起來(lái)
利用閉包
既然知道了閉包的特點(diǎn),我們?cè)趺蠢盟兀@里舉兩個(gè)例子
1.設(shè)置緩存
既然可以持久化變量,我們不妨可以將這個(gè)變量用作一個(gè)緩存,來(lái)存儲(chǔ)一些東西
cosnt cache = (function() {
const store = []
return {
get = function(key) {
return store[key]
},
set = function(key, value) {
store[key] = value
}
}
}())
cache.set('a', 10)
cache.get('a')
上面的例子定義了一個(gè)store,它一直被引用,不會(huì)被銷毀
2.保護(hù)變量
假如有個(gè)變量a,很重要,并且在對(duì)這個(gè)變量進(jìn)行操作的時(shí)候要注意其不能為負(fù)數(shù),這時(shí)候可以用閉包
cosnt foo= (function() {
const a= 0
return {
add= function(num) {
a+=num
},
reduce= function(num) {
a -= num
if(a < 0) {
// 操作
} else {
// 操作
}
}
}
}())
foo.add(3)
foo.reduce(2)
上面的代碼形成了閉包,防止在外部操作a變量時(shí)使a變量的值超出范圍
閉包需要注意的地方
閉包使得函數(shù)中的變量都被保存在內(nèi)存中,內(nèi)存消耗很大,濫用閉包會(huì)造成網(wǎng)頁(yè)性能問(wèn)題,在IE中導(dǎo)致內(nèi)存泄漏。解決方法是,在退出函數(shù)之前,將不使用的局部變量全部刪除。