Ily*_*sis 254 javascript
我有这个脚本:
for (var i = 1; i <= 2; i++) {
setTimeout(function() { alert(i) }, 100);
}
Run Code Online (Sandbox Code Playgroud)
但是3
两次都被提醒,而不是1
那时2
.
有没有办法传递i
,而不是将函数写为字符串?
Poi*_*nty 336
您必须安排为每个超时功能提供"i"的不同副本.
function doSetTimeout(i) {
setTimeout(function() { alert(i); }, 100);
}
for (var i = 1; i <= 2; ++i)
doSetTimeout(i);
Run Code Online (Sandbox Code Playgroud)
如果你不做这样的事情(并且这个想法有其他变化),那么每个定时器处理函数将共享相同的变量"i".当循环结束时,"i"的值是多少?这是3!通过使用中介函数,可以得到变量值的副本.由于超时处理程序是在该副本的上下文中创建的,因此它具有自己的私有"i".
编辑 - 随着时间的推移有一些评论,其中一些混淆是明显的,因为设置一些超时会导致处理程序同时发生.重要的是要了解设置计时器的过程- 呼叫setTimeout()
- 几乎没有时间.也就是说,告诉系统"请在1000毫秒后调用此函数"将几乎立即返回,因为在计时器队列中安装超时请求的过程非常快.
因此,如果发出一连串的超时请求,如OP中的代码和我的答案中的情况,并且每个时间延迟值相同,则一旦该时间量已经过去,所有定时器处理程序将一个接一个地快速连续调用.
如果你需要的是每隔一段时间调用一次处理程序,你可以使用setInterval()
,这被称为完全相同setTimeout()
但在重复延迟请求数量后会多次触发,或者你可以建立超时并乘以时间迭代计数器的值.也就是说,要修改我的示例代码:
function doScaledTimeout(i) {
setTimeout(function() {
alert(i);
}, i * 5000);
}
Run Code Online (Sandbox Code Playgroud)
(使用100
毫秒超时,效果不会非常明显,所以我将数字提高到5000.)值i
乘以基本延迟值,因此在循环中调用5次将导致延迟5秒,10秒,15秒,20秒和25秒.
更新
在2018年,有一个更简单的选择.由于新功能在范围中声明变量比函数更窄,原始代码如果这样修改就会起作用:
for (let i = 1; i <= 2; i++) {
setTimeout(function() { alert(i) }, 100);
}
Run Code Online (Sandbox Code Playgroud)
let
与此不同var
,声明本身会导致i
循环的每次迭代都有不同的声明.
Dar*_*rov 158
您可以使用立即调用的函数表达式(IIFE)来创建闭包setTimeout
:
for (var i = 1; i <= 3; i++) {
(function(index) {
setTimeout(function() { alert(index); }, i * 1000);
})(i);
}
Run Code Online (Sandbox Code Playgroud)
Meh*_*ash 32
这是因为!
该解决方案的通过使用执行的自功能(匿名一个或更好声明对于每次迭代单个范围IIFE)与具有的副本我在里面,这样的:
for (var i = 1; i <= 2; i++) {
(function(){
var j = i;
setTimeout(function() { console.log(j) }, 100);
})();
}
Run Code Online (Sandbox Code Playgroud)
那个更清洁的人
for (var i = 1; i <= 2; i++) {
(function(i){
setTimeout(function() { console.log(i) }, 100);
})(i);
}
Run Code Online (Sandbox Code Playgroud)
在每次迭代中使用IIFE(自执行函数)为每次迭代创建了一个新的范围,这使我们的超时函数回调有机会关闭每个迭代的新范围,其中一个具有正确的变量.它中的迭代值供我们访问.
har*_*rto 26
函数参数将setTimeout
关闭循环变量.循环在第一个超时之前结束并显示当前值i
,即3
.
因为JavaScript变量只有函数作用域,所以解决方案是将循环变量传递给设置超时的函数.您可以声明并调用这样的函数:
for (var i = 1; i <= 2; i++) {
(function (x) {
setTimeout(function () { alert(x); }, 100);
})(i);
}
Run Code Online (Sandbox Code Playgroud)
Mev*_*abu 10
您可以使用setTimeout的额外参数将参数传递给回调函数.
for (var i = 1; i <= 2; i++) {
setTimeout(function(j) { alert(j) }, 100, i);
}
Run Code Online (Sandbox Code Playgroud)
注意:这不适用于IE9及以下浏览器.
答案?
我正在将它用于动画以将项目添加到购物车 - 当点击时,购物车图标从产品"添加"按钮浮动到购物车区域:
function addCartItem(opts) {
for (var i=0; i<opts.qty; i++) {
setTimeout(function() {
console.log('ADDED ONE!');
}, 1000*i);
}
};
Run Code Online (Sandbox Code Playgroud)
注意持续时间是单位时间n epocs.
因此,从点击时刻开始,动画开始epoc(每个动画)是每个一秒单位乘以项目数的乘积.
epoc:https://en.wikipedia.org/wiki/Epoch_(reference_date )
希望这可以帮助!
你可以使用bind
方法
for (var i = 1, j = 1; i <= 3; i++, j++) {
setTimeout(function() {
alert(this);
}.bind(i), j * 100);
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
187856 次 |
最近记录: |