我們都知道一個概念。
在JS當中,一個函數可以訪問其外部的變量資源。
但以下這種情況會出錯。
function m1(){
var a = 100;
console.log(a++);
}
function m2(){
console.log(a++); //這里無法訪問a
}
如果,我們想在m2的作用域里,訪問m1里的變量,就像下面這樣:
首先,我們可以在m1的內部創建一個函數m3
function m1(){
var a = 100;
function m3(){
console.log(a++);
}
}
m3可以正常訪問a,接下來我們增加一個return操作。
function m1(){
var a = 100;
return function m3(){
console.log(a++);
}
}
既然有了返回值,那我們不妨接收一下,繼續編寫代碼如下:
function m1(){
var a = 100;
return function m3(){
console.log(a++);
}
}
var _m3 = m1();
我們執行了函數m1, 并將返回值賦值給_m3,
那么目前_m3和m3函數是等價的,即它們是同一個函數。
有了_m3,一切都好辦了。我們繼續編寫代碼
function m1(){
var a = 100;
return function m3(){
console.log(a++);
}
}
var _m3 = m1();
function m2(){
_m3();
}
因為_m3是全局變量,因此m2可以調用_m3
也就等價于m2間接的,訪問到了變量a
通常,我們管m3,叫做一個『 閉包函數 』
下面列舉幾個常見的閉包場景:
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();
}
}
})()
為了創造閉包,有時候會寫函數自調用
可以不這么麻煩么??
當然,那就是使用let。
例如
for(let i=0; i<list.length; p="" i++){<="">
let item = list[i];
item.onclick = function(){
console.log(i);
//觀察變量i的值
};
}
關于閉包的疑問
當函數m1執行完成的時候,內部的變量a,理論上應該被回收掉了。
可是為什么變量a依然可以被訪問呢?
主要是因為,m3還在引用它
垃圾回收器顯然不會回收一個依然被引用的變量。
除非這個變量,已經無人引用,即是說,它已經無法再內存里被找到。
此時才可以當做垃圾處理。
不過m3可以訪問變量a這種規則,并不是在所有編程語言里都生效的。因此,這也算是JS的特性之一。