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