什麼是閉包?
閉包就是能夠讀取其他函式內部變數的函式。
例如在javascript中,只有函式內部的子函式才能讀取區域性變數,所以閉包可以理解成“定義在一個函式內部的函式“。
在本質上,閉包是將函式內部和函式外部連線起來的橋樑。
程式碼演示:
當function
裡巢狀function
時,內部的function
可以訪問外部function
裡的變數
function fn(x) {
var tmp = 3;
function bar(y) {
alert(x + y + (++tmp));
}
bar(2);
}
fn(1)
複製程式碼
不管執行多少次,都會alert 7
,因為bar
能訪問fn
的引數x
,也能訪問fn
的變數tmp
。
但是,這並 不是 不是 不是 閉包
當你return
的是內部function
時,才是閉包
內部function
會close-over
外部function
的變數直到內部function
結束。
function fn(x) {
var tmp = 3;
return function (y) {
alert(x + y + (++tmp));
}
}
var bar = fn(1); // bar 現在是一個閉包
bar(2);
複製程式碼
上面的指令碼最終也會輸出alert 7
,因為雖然bar
不直接處於fn
的內部作用域,但bar
還是能訪問x
和tmp
。
但是,由於tmp
仍存在與bar
閉包的內部,所以它還是會自加1,而且你每次呼叫bar
時它都會自加1。
其實,我們其實可以建立不止一個閉包方法,比如return
它們的陣列,也可以把它們設定為全域性變數。它們全都指向相同的x
和相同的tmp
,而不是各自有一份副本。
一個需要關注的點:
JS裡處理object
時是用到引用傳遞的,那麼,你呼叫fn
時傳遞一個object
,fn
函式return
的閉包也會引用最初那個object
?
function fn(x) {
var tmp = 3;
return function (y) {
alert(x + y + tmp);
x.memb = x.memb ? x.memb + 1 : 1;
alert(x.memb);
}
}
var tar = new Number(1);
var bar = fn(tar); // bar 現在是一個引用了tar的閉包
bar(2);
複製程式碼
不出我們意料,每次執行bar(2)
,x.memb
都會自加1。但需要注意的是x
每次都指向同一個object
變數tar
。
這樣記憶體洩漏有關。
有一個不用return
關鍵字的閉包例子:
function closureExample(obj, text, timedelay) {
setTimeout(function() {
document.getElementById(objID).innerHTML = text;
}, timedelay);
}
closureExample(‘myDiv’, ‘Closure is created’, 500);
複製程式碼
總結:
JS裡的function
能訪問它們的:
- 引數
- 區域性變數或函式
- 外部變數
如果在一個函式中,又巢狀了一個函式,並且裡面這個函式引用外面的函式的變數,那麼就是閉包。
閉包的特點:
- 閉包可以產生記憶體洩露
- 閉包可以延長變數的生命週期