JavaScript 閉包究竟是什么
1.簡單的例子
首先從一個經典錯誤談起,頁面上有若干個div, 我們想給它們綁定一個onclick方法,于是有了下面的代碼
《div id=“divTest”》
《span》0《/span》 《span》1《/span》 《span》2《/span》 《span》3《/span》
《/div》
《div id=“divTest2”》
《span》0《/span》 《span》1《/span》 《span》2《/span》 《span》3《/span》
《/div》
$(document).ready(function() {
var spans = $(“#divTest span”);
for (var i = 0; i 《 spans.length; i++) {
spans[i].onclick = function() {
alert(i);
}
}
});
很簡單的功能可是卻偏偏出錯了,每次alert出的值都是4,簡單的修改就好使了
var spans2 = $(“#divTest2 span”);
$(document).ready(function() {
for (var i = 0; i 《 spans2.length; i++) {
?。╢unction(num) {
spans2[i].onclick = function() {
alert(num);
}
})(i);
}
});
2.內部函數
讓我們從一些基礎的知識談起,首先了解一下內部函數。內部函數就是定義在另一個函數中的函數。例如:
function outerFn () {
functioninnerFn () {}
}
innerFn就是一個被包在outerFn作用域中的內部函數。這意味著,在outerFn內部調用innerFn是有效的,而在outerFn外部調用innerFn則是無效的。下面代碼會導致一個JavaScript錯誤:
function outerFn() {
document.write(“Outer function《br/》”);
function innerFn() {
document.write(“Inner function《br/》”);
}
}
innerFn();
不過在outerFn內部調用innerFn,則可以成功運行:
function outerFn() {
document.write(“Outer function《br/》”);
function innerFn() {
document.write(“Inner function《br/》”);
}
innerFn();
}
outerFn();
2.1偉大的逃脫
JavaScript允許開發(fā)人員像傳遞任何類型的數據一樣傳遞函數,也就是說,JavaScript中的內部函數能夠逃脫定義他們的外部函數。
逃脫的方式有很多種,例如可以將內部函數指定給一個全局變量:
var globalVar;
function outerFn() {
document.write(“Outer function《br/》”);
function innerFn() {
document.write(“Inner function《br/》”);
}
globalVar = innerFn;
}
outerFn();
globalVar();
調用outerFn時會修改全局變量globalVar,這時候它的引用變?yōu)閕nnerFn,此后調用globalVar和調用innerFn一樣。這時在outerFn外部直接調用innerFn仍然會導致錯誤,這是因為內部函數雖然通過把引用保存在全局變量中實現了逃脫,但這個函數的名字依然只存在于outerFn的作用域中。
也可以通過在父函數的返回值來獲得內部函數引用
function outerFn() {
document.write(“Outer function《br/》”);
function innerFn() {
document.write(“Inner function《br/》”);
}
return innerFn;
}
var fnRef = outerFn();
fnRef();
這里并沒有在outerFn內部修改全局變量,而是從outerFn中返回了一個對innerFn的引用。通過調用outerFn能夠獲得這個引用,而且這個引用可以可以保存在變量中。
這種即使離開函數作用域的情況下仍然能夠通過引用調用內部函數的事實,意味著只要存在調用內部函數的可能,JavaScript就需要保留被引用的函數。而且JavaScript運行時需要跟蹤引用這個內部函數的所有變量,直到最后一個變量廢棄,JavaScript的垃圾收集器才能釋放相應的內存空間(紅色部分是理解閉包的關鍵)。
說了半天總算和閉包有關系了,閉包是指有權限訪問另一個函數作用域的變量的函數,創(chuàng)建閉包的常見方式就是在一個函數內部創(chuàng)建另一個函數,就是我們上面說的內部函數,所以剛才說的不是廢話,也是閉包相關的 ^_^
評論