简体   繁体   English

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

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

When I run the following code in console: 当我在控制台中运行以下代码时:

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

The alert shows undefined. 警报显示未定义。 Moreover, I expect the delay of timeout function to be increased after every iteration; 而且,我希望每次迭代后超时功能的延迟都会增加; but that doesn't happen. 但这不会发生。 The timeout function should run first after 5sec then after then 10sec and then 15sec and so on. 超时功能应首先在5秒后运行,然后在10秒后再运行15秒,依此类推。

Why is undefined alerted and why isn't delay increased after each iteration? 为什么未定义的警报会发出警报,为什么每次迭代后延迟都不会增加?

Since k in the local scope of timeout function, it should be visible inside it. 由于k在超时功能的本地范围内,因此它应该在其中可见。

It's undefined because the timer mechanism setTimeout hooks the function to doesn't call the function you give it with any arguments (by default), and you've declared k as the function argument. 它是undefined因为计时器机制setTimeout会将函数挂接到该函数,而不会调用带有任何参数的函数(默认情况下),并且已将k声明为函数参数。 When you call a JavaScript function with fewer arguments than it declares, the value of those arguments is undefined . 当您调用的JavaScript函数的参数少于其声明的参数时,这些参数的值是undefined So the argument k shadows (hides) the loop variable k , and you always see undefined . 因此, 参数 k遮蔽(隐藏) 循环变量 k ,您始终会看到undefined

To fix it, don't declare k as a function argument: 要解决此问题,请不要将k声明为函数参数:

for (var k = 0; k < 36; k++){
    setTimeout(function(){ alert(k)}, k*5000);
    // No k here -------^
}

Example (using 500 instead of 5000): 示例(使用500代替5000):

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

But , then you'll have to fix a new problem ( the one addressed by this question and its answers ): The value of k that all of those callbacks see will be the same (36), because they see k 's value as of when they're called (later, once the loop is over), not when they're created. 但是 ,则您必须修复一个新问题( 此问题及其答案解决的问题 ):所有这些回调看到的k的值将相同 (36),因为它们将k的值视为何时调用它们(后来,一旦循环结束),而不是何时创建它们。

In ES5 and earlier, I would solve that like this: 在ES5及更早版本中,我将这样解决:

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

Example: 例:

 function createHandler(k) { return function(){ console.log(k)}; } for (var k = 0; k < 36; k++){ setTimeout(createHandler(k), k*500); } 

...although many would create that createHandler function repeatedly in the loop: ...尽管许多人会在循环中重复创建该createHandler函数:

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

Example: 例:

 for (var k = 0; k < 36; k++){ setTimeout(function(innerk) { return function() { console.log(innerk); } }(k), k*500); } 

In ES2015+ ("ES6" and above), I'd solve it like this: 在ES2015 +(“ ES6”及更高版本)中,我会这样解决:

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

...because when you use let within the for like that, it creates a new k for each iteration with a value that doesn't change. ...因为在诸如此类的for使用let时,它将为每次迭代创建一个新的k ,其值保持不变。

Example: 例:

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

You can pass the k parameter in 2 ways: 您可以通过两种方式传递k参数:

for(var k = 0; k < 36; k++){
    setTimeout(function(k){ alert(k); }, k * 5000, k); // but is not supported in IE9 and earlier
}

or better wrap it into a function call: 或更好地将其包装到一个函数调用中:

for (var k = 0; k < 36; k++) _setTimeout(k);

function _setTimeout(k) {
    setTimeout(function(){ alert(k); }, k * 5000);
}

you pass k to the callback function of setTimeOut but it takes nothing.So removing the parameter k will work. 您可以将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