我有这个脚本:

for (var i = 1; i <= 2; i++) {
    setTimeout(function() { alert(i) }, 100);
}

但是3被提醒两次,而不是1和2。

有没有一种方法传递i,而不把函数写成字符串?


当前回答

您必须为每个超时函数安排一个不同的“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。

其他回答

我也遇到过同样的问题这就是我解决的方法。

假设我想要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

你可以使用bind方法

for (var i = 1, j = 1; i <= 3; i++, j++) {
    setTimeout(function() {
        alert(this);
    }.bind(i), j * 100);
}

答案?

我用它来做一个添加物品到购物车的动画——当点击产品“添加”按钮时,一个购物车图标浮动到购物车区域:

function addCartItem(opts) {
    for (var i=0; i<opts.qty; i++) {
        setTimeout(function() {
            console.log('ADDED ONE!');
        }, 1000*i);
    }
};

时间单位为单位乘以n周期。

因此,从点击时刻开始,动画开始epoc(每个动画的)是每个一秒单位乘以项目数量的乘积。

epoc: https://en.wikipedia.org/wiki/Epoch_ (reference_date)

希望这能有所帮助!

你可以使用立即调用的函数表达式(IIFE)来创建一个围绕setTimeout的闭包:

for (var i = 1; i <= 3; i++) { (函数(索引) { setTimeout(function() { alert(index); }, i * 1000); })(i); }

您必须为每个超时函数安排一个不同的“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。