var fnArr = [];
for (var i = 0; i < 10; i ++) {
fnArr[i] = function(){
return i;
};
}
i = 5
console.log( fnArr[3]() ); //5
這里居然打出5,為什么不是10呢?為什么不是3呢?有很多人知道i引用的是全局變量i,可以用閉包解決這個問題,那么為什么會這樣呢?還牽扯到了函數(shù)的執(zhí)行原理,因為函數(shù)又是一個對象,對象會被存到堆內存中,所以函數(shù)當函數(shù)沒有執(zhí)行的時候,就把函數(shù)當做字符串放在堆內存中,數(shù)組中存儲的,其實只是指向這個堆內存的指針,i并沒有傳進去,執(zhí)行的時候i才被傳進去
fnArr[0] = function(){
return i
}
fnArr[1] = function(){
return i
}
直到函數(shù)執(zhí)行的時候瀏覽器才會解析這段字符串,把他當做函數(shù)來執(zhí)行,所以當我們執(zhí)行函數(shù)的時候,i已經(jīng)循環(huán)到10了,i取到的就是全局變量10,之后我們把i賦值為5,i取到的就是5了。
這時候我們就發(fā)現(xiàn)一個問題,我們想取到每一個i值,怎么辦呢?可以把它放到局部作用域,這時候就輪到閉包大展身手了,閉包的作用就是創(chuàng)建一個局部作用域,保存變量
所以有了之后的一系列的閉包寫法
所以這個題的重點不在于閉包,而在于你對于函數(shù)執(zhí)行了解的程度,如果你能完全理解為什么i變成10,而不是只知道i為10,那么之后寫成閉包就是在自然不過的事了,因為你知道這段代碼有什么問題,那么就只剩解決問題了,可是,程序員的天職不就是解決問題嗎?
最后附一下解決辦法:
方法1:
//自執(zhí)行函數(shù)
var fnArr = [];
for (var i = 0; i < 10; i ++) {
fnArr[i] = function(i){
return function(){
return i;
}
}(i)
}
console.log( fnArr[3]() ); //3
方法2:
//自執(zhí)行函數(shù)
var fnArr = [];
for (var i = 0; i < 10; i ++) {
fnArr[i] = (function(){
var temp = i
return function(){
return temp
}
})()
}
console.log( fnArr[3]() ); //3
方法3:
var fnArr = [];
for (var i = 0; i < 10; i ++) {
!function(i){
fnArr[i] = function(){
return i;
}
}(i)
}
console.log( fnArr[3]() ); //3
方法4:
var fnArr = [];
for (let i = 0; i < 10; i ++) {
fnArr[i] = function(){
return i;
};
}
console.log( fnArr[3]() ); //3