[英]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.