引入
for (var i=1; i<=5; i++) {
setTimeout( function timer() {
console.log( i );
}, i*1000 );
}
在没有仔细分析的情况下,我们对这段代码行为的预期是分别输出数字 1~5,每秒一次,每次一个。
但实际上是,以每秒一次的频率输出了五次 6。
为何出现6?
循环终止条件是i<=5,因此条件成立的i最小值为6。
简单一想,每次迭代都会创建一个setTimeout的回调函数,这些函数又只会在循环条件结束时才执行,所有才会每次输出一个6;
仔细一想,根据作用域的工作原理,通过迭代定义的五个函数他们都被封闭在一个共享的全局作用域中,他们共享一个i值。
方案
接下来分享几种解决无法获取for循环中i的实时值方法:
立即执行函数表达式(IIFE):
IIFE 会通过声明并立即执行一个函数来创建作用域
for (var i=1; i<=5; i++) {
(function(j) { //每次迭代中我们都使用j来存储i的值
setTimeout( function timer() {
console.log( j );
}, j*1000 );
})( i );
}
块作用域:
let代替var,每次执行都是一个全新的独立的块作用域,用let声明的变量传入到 for循环体的作用域后,不会发生改变,不受外界的影响。
for (let i=1; i<=5; i++) {
setTimeout( function timer() {
console.log( i );
}, i*1000 );
}