1. 閉包的概念
據我們所知,區域性變數在函式退出之後就不佔據記憶體空間,但存在一種特殊的函式,能使區域性變數在函式退出之後繼續佔據記憶體,為外部函式所呼叫,這個特殊的函式就是閉包
。那麼閉包是怎麼做到將區域性函式一直佔據記憶體的呢?看看下面的例子。
function a(){
var Aitem=2;//定義區域性變數item
function b() { //定義內部函式b()
alert(Aitem);
}
b();
}
a();//結果是2
複製程式碼
2. 閉包的機理
從上可以看出內部函式可以讀取外部函式的區域性變數。此時的內部函式的作用域僅限於外部函式a(),只有通過呼叫外部函式a()才可以執行內部函式b()。當外部函式執行結束,內部函式的記憶體也將清除。但是如果我們將內部函式賦給一個全域性變數
,那麼內部函式將從區域性變數
轉化成全域性變數
。即使外部函式退出了,作為全域性變數的內部函式也將儲存在記憶體中。那麼如何讓內部函式成為全域性變數呢?
function a(x){
var Aitem=2;//定義區域性變數item
return function b(y) { //a函式結果返回一個b函式
alert(x+y+(++Aitem));
}
}
var closure=a(1);//將a(1)return的結果b()賦給全域性變數,closure=b(y){ alert(1+y+(++Aitem))}
closure(1);//彈出5;closure(1)=b(y){ alert(1+1+(++2))}
closure(1);//彈出6;closure(1)=b(y){ alert(1+1+(++3))}
複製程式碼
上例中的closure()函式即閉包
。第一次closure(1)中Aitem=2
,第二次closure(1)中Aitem=3
,可以看出item
這個區域性變數在a()退出以後並沒有被清除,而是像一個全域性變數一樣一直儲存在記憶體中。這就是閉包的神奇所在。closure()閉包依賴於b(y),而b(y)又是a(x)的區域性函式,故closure()閉包可以實時訪問a(x)的區域性變數。如果沒有將內部函式裝化成全域性變數的話,就形不成閉包,請看下面的例子:
function a(x){
var Aitem=2;//定義區域性變數item
function b(y) { //定義區域性函式b
alert(x+y+(++Aitem));
}
b(1);//在a()內部執行b(1);即alert(x+1+(++2))
}
a(1);//彈出5;即alert(1+1+(++2))
複製程式碼
上例沒有將區域性函式b()賦給全域性變數,在a(1)執行以後b()就不復存在,Aitem也無從獲取。
3. 總結
閉包是可以讀取其他函式內部變數的函式,是外部函式和內部函式的一座橋樑。
閉包擁有兩個作用:
- 使區域性變數keep alive
- 讀取其他函式的區域性變數
閉包的缺點:
- 常駐記憶體,造成記憶體的浪費