小白都能看懂的閉包(closure)
前言:
閉包(closure)是Javascript語言的一個難點,也是它的特色,很多高階應用都要依靠閉包實現。
要理解閉包,首先必須理解Javascript特殊的變數作用域。
變數的作用域無非就是兩種:全域性變數和區域性變數。
Javascript語言的特殊之處,就在於函式內部可以直接讀取全域性變數。
1. 關於全域性變數 和 區域性變數的 理解:
函式外面: var a = 20; 此處var宣告的a是一個全域性變數
函式內部:function getAll() {
//如果是 var 宣告的,則是區域性變數 (與函式外面宣告的相反 )
var a = 20;
//如果是直接寫的(省去var宣告的),則是全域性變數
a = 20
}
訪問範圍:
全域性變數,在整個script中,都可以訪問到;
但是區域性變數只能在函式內部訪問到;函式外部是不能訪問到的。
有時候,想要在全域性訪問到函式內部的區域性變數,要怎麼辦?
——閉包,可以實現這一點。
2. 閉包(closure):
何為閉包?
在一個函式中寫入另外一個函式,並且可以訪問到這個函式的區域性變數的函式,這就是閉包。
在js中,只有一個函式內部的子函式才可以讀取區域性變數,所以,也可以把閉包理解為“定義在一個函式內部的函式”。
(本質上,閉包就是講函式內部和函式外部連結的一座橋樑。)
function fn1(){
var a = 20;
return function fn2(){
alert(a);
}
}
fn1()();
此處的 fn2函式就是閉包函式。
3. 閉包的作用:
第一:可以讀取一個函式內部的函式,
第二:避免“垃圾回收機制”回收,因為子函式會返回一個全域性變數,又會呼叫父函式的區域性變數,兩個變數相互呼叫;
所以,兩個函式都不會被清除。
4、關於閉包中this的指向問題( 進階版)。
程式碼一:
var name = 'The window ';
var object = {
name: ' my object',
fn1 : function(){
alert('1' + this.name); //此處this.name為 my object (因為會繼承object)
return function(){
alert('2' + this.name); //此處this.name為The window (沒有執行是上下文,所以,找到了windows )
return this.name;
}
}
}
object.fn1()();
難點:紅色部分打印出來的為什麼是“The window” ?
解釋:
我們可以換種寫法:
var obj = object.fn1()();
obj();
這裡的obj()是函式體 function() { return this.name };
此處的obj指向的是window,所以this.name是The.window
程式碼二:
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
var that = this;
alert(that.name); //?
return function(){
alert(this.name); //?
alert(that.name); //?
return that.name;
};
}
};
object.getNameFunc()();
解釋:這裡只要是that.name都是指向的“My Object”;
因為,紅色的那行程式碼,把this的指向做了儲存。
但是如果用的是,this.name依然指向的是windows(可以參考程式碼一中的解釋)。