当我在控制台中运行以下代码时:
for(var k = 0; k < 36; k++){
setTimeout(function(k){ alert(k)}, k*5000);
}
警报显示未定义。此外,我希望在每次迭代后增加超时功能的延迟;但这不会发生。超时功能应该在5秒后首先运行,然后在10秒后再运行15秒,依此类推。
为什么未定义警报,为什么在每次迭代后没有延迟增加?
由于本地超时功能范围内的k
,它应该在其中可见。
答案 0 :(得分:6)
它是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 -------^
}
示例(使用500而不是5000):
for (var k = 0; k < 36; k++){
setTimeout(function(){ console.log(k)}, k*500);
// No k here -------^
}
但是,那么您必须解决一个新问题(the one addressed by this question and its answers):所有这些回调看到的k
的值都是相同的(36),因为他们看到k
的值是在他们被调用时(稍后,一旦循环结束),而不是在他们被创建时。
在ES5及更早版本中,我会这样解决:
function createHandler(k) {
return function(){ alert(k)};
}
for (var k = 0; k < 36; k++){
setTimeout(createHandler(k), k*5000);
}
示例:
function createHandler(k) {
return function(){ console.log(k)};
}
for (var k = 0; k < 36; k++){
setTimeout(createHandler(k), k*500);
}
...虽然很多人会在循环中重复创建createHandler
函数:
for (var k = 0; k < 36; k++){
setTimeout(function(innerk) {
return function() { alert(innerk); }
}(k), k*5000);
}
示例:
for (var k = 0; k < 36; k++){
setTimeout(function(innerk) {
return function() { console.log(innerk); }
}(k), k*500);
}
在ES2015 +(“ES6”及以上版本)中,我会这样解决:
for (let k = 0; k < 36; k++){
setTimeout(() => { alert(k); }, k*5000);
}
...因为当您在let
内使用for
时,它会为每次迭代创建一个新的k
,其值不会改变。
示例:
// REQUIRES ES2015+ SUPPORT
for (let k = 0; k < 36; k++){
setTimeout(() => { console.log(k); }, k*500);
}
答案 1 :(得分:2)
您可以通过两种方式传递k
参数:
for(var k = 0; k < 36; k++){
setTimeout(function(k){ alert(k); }, k * 5000, k); // but is not supported in IE9 and earlier
}
或更好地将其包装到函数调用中:
for (var k = 0; k < 36; k++) _setTimeout(k);
function _setTimeout(k) {
setTimeout(function(){ alert(k); }, k * 5000);
}
答案 2 :(得分:-1)
您将 k 传递给setTimeOut的回调函数,但它不需要任何内容。删除参数k将起作用。
for(var k = 0; k < 36; k++){
setTimeout(function(){ alert(k)}, k*5000);
}