use*_*782 0 javascript scope for-loop function settimeout
当我在控制台中运行以下代码时:
for(var k = 0; k < 36; k++){
setTimeout(function(k){ alert(k)}, k*5000);
}
Run Code Online (Sandbox Code Playgroud)
警报显示未定义.此外,我希望在每次迭代后增加超时功能的延迟; 但这不会发生.超时功能应在5秒后首先运行,然后在10秒后再运行15秒,依此类推.
为什么未定义警报,为什么在每次迭代后没有延迟增加?
由于k在本地超时功能范围内,它应该在其内部可见.
这是undefined因为定时器机制setTimeout挂钩函数不会调用你给它的函数任何参数(默认情况下),并且你已经声明k为函数参数.当您使用少于声明的参数调用JavaScript函数时,这些参数的值为undefined.所以参数 k阴影(隐藏)循环变量 k,你总是看到undefined.
要修复它,不要声明k为函数参数:
for (var k = 0; k < 36; k++){
setTimeout(function(){ alert(k)}, k*5000);
// No k here -------^
}
Run Code Online (Sandbox Code Playgroud)
示例(使用500而不是5000):
for (var k = 0; k < 36; k++){
setTimeout(function(){ console.log(k)}, k*500);
// No k here -------^
}Run Code Online (Sandbox Code Playgroud)
但是,那么你将不得不解决一个新问题(这个问题及其答案所解决的问题):k所有这些回调看到的价值都是相同的(36),因为他们看到k的是什么时候的价值它们被调用(后来,一旦循环结束),而不是它们被创建时.
在ES5和更早版本中,我会像这样解决:
function createHandler(k) {
return function(){ alert(k)};
}
for (var k = 0; k < 36; k++){
setTimeout(createHandler(k), k*5000);
}
Run Code Online (Sandbox Code Playgroud)
例:
function createHandler(k) {
return function(){ console.log(k)};
}
for (var k = 0; k < 36; k++){
setTimeout(createHandler(k), k*500);
}Run Code Online (Sandbox Code Playgroud)
...虽然很多人会createHandler在循环中重复创建该函数:
for (var k = 0; k < 36; k++){
setTimeout(function(innerk) {
return function() { alert(innerk); }
}(k), k*5000);
}
Run Code Online (Sandbox Code Playgroud)
例:
for (var k = 0; k < 36; k++){
setTimeout(function(innerk) {
return function() { console.log(innerk); }
}(k), k*500);
}Run Code Online (Sandbox Code Playgroud)
在ES2015 +("ES6"及以上版本)中,我会像这样解决:
for (let k = 0; k < 36; k++){
setTimeout(() => { alert(k); }, k*5000);
}
Run Code Online (Sandbox Code Playgroud)
...因为当你let在for类似的东西中使用时,它会k为每次迭代创建一个新值,其值不会改变.
例:
// REQUIRES ES2015+ SUPPORT
for (let k = 0; k < 36; k++){
setTimeout(() => { console.log(k); }, k*500);
}Run Code Online (Sandbox Code Playgroud)