我們都知道一個(gè)概念。
在JS當(dāng)中,一個(gè)函數(shù)可以訪問其外部的變量資源。
但以下這種情況會(huì)出錯(cuò)。
function m1(){
var a = 100;
console.log(a++);
}
function m2(){
console.log(a++); //這里無法訪問a
}
如果,我們想在m2的作用域里,訪問m1里的變量,就像下面這樣:
首先,我們可以在m1的內(nèi)部創(chuàng)建一個(gè)函數(shù)m3
function m1(){
var a = 100;
function m3(){
console.log(a++);
}
}
m3可以正常訪問a,接下來我們?cè)黾右粋€(gè)return操作。
function m1(){
var a = 100;
return function m3(){
console.log(a++);
}
}
既然有了返回值,那我們不妨接收一下,繼續(xù)編寫代碼如下:
function m1(){
var a = 100;
return function m3(){
console.log(a++);
}
}
var _m3 = m1();
我們執(zhí)行了函數(shù)m1, 并將返回值賦值給_m3,
那么目前_m3和m3函數(shù)是等價(jià)的,即它們是同一個(gè)函數(shù)。
有了_m3,一切都好辦了。我們繼續(xù)編寫代碼
function m1(){
var a = 100;
return function m3(){
console.log(a++);
}
}
var _m3 = m1();
function m2(){
_m3();
}
因?yàn)開m3是全局變量,因此m2可以調(diào)用_m3
也就等價(jià)于m2間接的,訪問到了變量a
通常,我們管m3,叫做一個(gè)『 閉包函數(shù) 』
下面列舉幾個(gè)常見的閉包場(chǎng)景:
01
for(var i=0; i<list.length; p="" i++){<="">
var item = list[i];
item.onclick = (function(num){
return function(){
//......
}
})(i);
}
02
function (){
var that = this;
setTimeout(function(){
//......
},2000)
}
03
function User(){
var _age = 0;
this.getAge = function(){
return _age;
}
this.setAge = function(age){
this._age = age;
}
}
04
(function(){
var cache = [...];
return {
get : function(){
//...
}
};
})()
05
(function(){
var t = null;
return function(){
if(!t){
t = create();
}
}
})()
為了創(chuàng)造閉包,有時(shí)候會(huì)寫函數(shù)自調(diào)用
可以不這么麻煩么??
當(dāng)然,那就是使用let。
例如
for(let i=0; i<list.length; p="" i++){<="">
let item = list[i];
item.onclick = function(){
console.log(i);
//觀察變量i的值
};
}
關(guān)于閉包的疑問
當(dāng)函數(shù)m1執(zhí)行完成的時(shí)候,內(nèi)部的變量a,理論上應(yīng)該被回收掉了。
可是為什么變量a依然可以被訪問呢?
主要是因?yàn)?,m3還在引用它
垃圾回收器顯然不會(huì)回收一個(gè)依然被引用的變量。
除非這個(gè)變量,已經(jīng)無人引用,即是說,它已經(jīng)無法再內(nèi)存里被找到。
此時(shí)才可以當(dāng)做垃圾處理。
不過m3可以訪問變量a這種規(guī)則,并不是在所有編程語言里都生效的。因此,這也算是JS的特性之一。