for迴圈i,最終結果是10的問題
阿新 • • 發佈:2019-01-06
連線: https://segmentfault.com/q/1010000003712016
今天做一個迴圈想得到1,2,3...10的輸出結果。自己寫的放棄了,然後看到了這麼一個方案,但不是很理解,不知道自己哪一方面知識的欠缺,求大神解答!!!
var funcs = [];
for (var i=0; i < 10; i++) {
funcs.push((function(value) {
return function() {
console.log(value);
}
}(i)));
}
funcs.forEach(function(func ) {
func(); // outputs 0, then 1, then 2, up to 9
});
自己訪問自己的變數i,在每一個迴圈中都傳入一個i值???
知識點:
詞法作用域
閉包
立即執行函式表示式
一步一步來,首先,你寫的應該是這樣:
for (var i=0; i < 10; i++) {
funcs.push(function(i) {
return function() {
console.log(i);
}
});
}
分析:9從哪裡來?9為迴圈i的最終值。函式在迴圈結束後才呼叫,所以每次都是9;
但不符合你的目的(從1,2,3 ... 9)依次打印出來,問題出在它們被封閉在一個共享的全域性作用域中,實際上就只有一個i,所以都是9。
還是不明白?看這裡:假設迴圈在全域性環境中,那麼迴圈中的i(var i=0
思考:那我們給建立各自的作用域不就行了,這樣就引入了立即執行函式表示式(題中為匿名函式表示式)來建立各自的作用域。所以改進程式碼為:
for (var i=0; i < 10; i++) {
funcs.push((function(i) {
return function() {
console.log(i);
}
}()));
}
but,結果還是一樣都是9,why?因為我們建立了空白的作用域,我們要傳入東西才行啊,so:
for (var i=0; i < 10; i++) {
funcs.push((function(value) {
return function() {
console.log(value);
}
}(i)));
}
這樣就將 i 傳進去了,就是這麼任性。。。
補充1:ES6已經有let可以建立塊作用域了,所以,上面可以這麼寫:
for (let i=0; i < 10; i++) {
funcs.push(function(i) {
return function() {
console.log(i);
}
});
}
建議你看看剛出不久的《你不知道的JavaScript上卷》,這部分講得很透徹~
補充2:看完3樓,發現漏了i++。。i為10
首先看下失敗的程式碼:
var funcs = []
for (var i = 0; i < 3; i++) {
funcs.push(function() {
console.log(i)
})
}
funcs[0]() // 3
funcs[1]() // 3
funcs(2)() // 3
為什麼這樣呢?其實如果剝離掉for
語句,以上程式碼會像這樣子:
var funcs = [],
i = 0
funcs.push(function() {
console.log(i)
})
i++
funcs.push(function() {
console.log(i)
})
i++
funcs.push(function() {
console.log(i)
})
i++
funcs[0]() // 3
funcs[1]() // 3
funcs[2]() // 3
為什麼會輸出上面的結果顯而易見了吧。
那麼要達到所需要的要求怎麼做呢?通常就在push
方法中傳入一個自執行函式,
並且將i
作為自執行函式的引數,以供作用於它內部。
var funcs = [],
i = 0
funcs.push((function(i){
return function() {
console.log(i)
}
}(i)))
i++
funcs.push((function(i){
return function() {
console.log(i)
}
}(i)))
i++
funcs[0]() // 0
funcs[1]() // 1
現在還原到for
語句的形式:
var funcs = []
for (var i = 0; i < 3; i++) {
funcs.push((function(i) {
return function() {
console.log(i)
}
}(i)))
}
// 這裡會依次輸出 0, 1, 2
funcs.forEach(function(f){
f()
})
Over~