for 循环中的 setTimeout 不打印连续值
我有这个脚本:
for (var i = 1; i <= 2; i++) {
setTimeout(function() { alert(i) }, 100);
}
但是两次都发出警报,而不是然后。3
1
2
有没有办法传递,而不把函数写成字符串?i
我有这个脚本:
for (var i = 1; i <= 2; i++) {
setTimeout(function() { alert(i) }, 100);
}
但是两次都发出警报,而不是然后。3
1
2
有没有办法传递,而不把函数写成字符串?i
您必须为每个超时函数安排一个不同的“i”副本。
function doSetTimeout(i) {
setTimeout(function() { alert(i); }, 100);
}
for (var i = 1; i <= 2; ++i)
doSetTimeout(i);
如果您不执行此类操作(并且同一想法还有其他变体),则每个计时器处理程序函数将共享相同的变量“i”。循环完成后,“i”的值是多少?是3!通过使用中介函数,可以创建变量值的副本。由于超时处理程序是在该副本的上下文中创建的,因此它有自己的私有“i”可供使用。
编辑 - 随着时间的推移,有一些评论,其中一些混淆是显而易见的,因为设置几个超时会导致处理程序同时触发。重要的是要了解,设置计时器的过程 - 调用 - 几乎不需要任何时间。也就是说,告诉系统,“请在1000毫秒后调用此函数”将几乎立即返回,因为在计时器队列中安装超时请求的过程非常快。setTimeout()
因此,如果发出了一连串的超时请求,就像OP和我的回答中的代码中的情况一样,并且每个请求的时间延迟值都是相同的,那么一旦经过该时间量,所有计时器处理程序将被快速连续地调用。
如果您需要的是按时间间隔调用处理程序,则可以使用 ,其调用方式与 相同,但在请求量的重复延迟后将触发多次,或者您可以建立超时并将时间值乘以迭代计数器。也就是说,修改我的示例代码:setInterval()
setTimeout()
function doScaledTimeout(i) {
setTimeout(function() {
alert(i);
}, i * 5000);
}
(使用毫秒超时,效果不会很明显,所以我将数字提高到5000。的值乘以基本延迟值,因此在循环中调用 5 次将导致 5 秒、10 秒、15 秒、20 秒和 25 秒的延迟。100
i
更新
在2018年,有一个更简单的选择。有了在比函数更窄的范围内声明变量的新功能,如果修改,原始代码将起作用:
for (let i = 1; i <= 2; i++) {
setTimeout(function() { alert(i) }, 100);
}
与 不同,声明本身将导致循环的每次迭代都有一个不同的声明。let
var
i
您可以使用立即调用的函数表达式 (IIFE) 在 以下周围创建闭包:setTimeout
for (var i = 1; i <= 3; i++) {
(function(index) {
setTimeout(function() { alert(index); }, i * 1000);
})(i);
}