繁体   English   中英

为什么在setTimeout函数中看不到for循环中定义的变量?

[英]Why isn't a variable defined in for loop not visible in setTimeout function?

当我在控制台中运行以下代码时:

for(var k = 0; k < 36; k++){
    setTimeout(function(k){ alert(k)}, k*5000);
}

警报显示未定义。 而且,我希望每次迭代后超时功能的延迟都会增加; 但这不会发生。 超时功能应首先在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 -------^
}

示例(使用500代替5000):

 for (var k = 0; k < 36; k++){ setTimeout(function(){ console.log(k)}, k*500); // No k here -------^ } 

但是 ,则您必须修复一个新问题( 此问题及其答案解决的问题 ):所有这些回调看到的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);
}

...因为在诸如此类的for使用let时,它将为每次迭代创建一个新的k ,其值保持不变。

例:

 // REQUIRES ES2015+ SUPPORT for (let k = 0; k < 36; k++){ setTimeout(() => { console.log(k); }, k*500); } 

您可以通过两种方式传递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);
}

您可以将k传递给setTimeOut的回调函数,但它什么也不做。因此删除参数k即可。

for(var k = 0; k < 36; k++){
setTimeout(function(){ alert(k)}, k*5000);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM