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