我有这个脚本:
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,而不把函数写成字符串?
当前回答
你可以使用bind方法
for (var i = 1, j = 1; i <= 3; i++, j++) {
setTimeout(function() {
alert(this);
}.bind(i), j * 100);
}
其他回答
您必须为每个超时函数安排一个不同的“i”副本。
函数 doSetTimeout(i) { setTimeout(function() { 警报(i); }, 100); } for (var i = 1; i <= 2; ++i) doSetTimeout(i);
如果你不这样做(同样的想法还有其他变体),那么每个计时器处理函数将共享相同的变量“i”。当循环结束时,i的值是多少?这是3 !通过使用中介函数,生成变量值的副本。由于超时处理程序是在该副本的上下文中创建的,因此它有自己的私有“i”可以使用。
编辑:
There have been a couple of comments over time in which some confusion was evident over the fact that setting up a few timeouts causes the handlers to all fire at the same time. It's important to understand that the process of setting up the timer — the calls to setTimeout() — take almost no time at all. That is, telling the system, "Please call this function after 1000 milliseconds" will return almost immediately, as the process of installing the timeout request in the timer queue is very fast. Thus, if a succession of timeout requests is made, as is the case in the code in the OP and in my answer, and the time delay value is the same for each one, then once that amount of time has elapsed all the timer handlers will be called one after another in rapid succession.
If what you need is for the handlers to be called at intervals, you can either use setInterval(), which is called exactly like setTimeout() but which will fire more than once after repeated delays of the requested amount, or instead you can establish the timeouts and multiply the time value by your iteration counter. That is, to modify my example code: function doScaledTimeout(i) { setTimeout(function() { alert(I); }, i * 5000); } (With a 100 millisecond timeout, the effect won't be very obvious, so I bumped the number up to 5000.) The value of i is multiplied by the base delay value, so calling that 5 times in a loop will result in delays of 5 seconds, 10 seconds, 15 seconds, 20 seconds, and 25 seconds.
更新
在2018年,有一个更简单的选择。有了在比函数更窄的作用域中声明变量的新能力,如果这样修改,原始代码将正常工作:
For(令I = 1;I <= 2;我+ +){ setTimeout(函数(){ 警报(我) }, 100); }
与var不同,let声明本身会导致循环的每次迭代都有一个不同的i。
你可以使用立即调用的函数表达式(IIFE)来创建一个围绕setTimeout的闭包:
for (var i = 1; i <= 3; i++) { (函数(索引) { setTimeout(function() { alert(index); }, i * 1000); })(i); }
这是因为!
超时函数 回调在循环完成后都运行良好。事实上, 作为计时器,即使它是setTimeout(.., 0),所有 这些函数回调在完成后仍然严格运行 这就是为什么有3个被反射了! 这两个函数都有定义 在每个循环迭代中,分别在相同的共享全局上关闭 范围,实际上只有一个I在里面。
解决方案通过使用执行的自我函数(匿名或更好的IIFE)来声明每个迭代的单一作用域,并在其中有一个i的副本,如下所示:
for (var i = 1; i <= 2; i++) {
(function(){
var j = i;
setTimeout(function() { console.log(j) }, 100);
})();
}
更干净的一个
for (var i = 1; i <= 2; i++) {
(function(i){
setTimeout(function() { console.log(i) }, 100);
})(i);
}
在每个迭代中使用IIFE(自执行函数)为每个迭代创建了一个新的作用域 迭代,这给了我们的超时函数回调机会 为每个迭代关闭一个具有变量的新作用域 有正确的每次迭代值供我们访问。
你可以使用bind方法
for (var i = 1, j = 1; i <= 3; i++, j++) {
setTimeout(function() {
alert(this);
}.bind(i), j * 100);
}
我也遇到过同样的问题这就是我解决的方法。
假设我想要12个间隔为2秒的延迟
function animate(i){
myVar=setTimeout(function(){
alert(i);
if(i==12){
clearTimeout(myVar);
return;
}
animate(i+1)
},2000)
}
var i=1; //i is the start point 1 to 12 that is
animate(i); //1,2,3,4..12 will be alerted with 2 sec delay