在 setTimeout 内部循环中保留参数值

Preserve parameter value in setTimeout inside loop

提问人:Shambo Basu 提问时间:6/12/2021 更新时间:6/12/2021 访问量:52

问:

我正在学习 setTimeout,并尝试在循环中打印一个有延迟的数组,每次迭代后,不同索引处的值都会发生变化。我的原始数组是 [1,2,3,4,5]。我希望输出是这样的:

enter image description here

我知道闭包可以与 setTimeout 一起使用,以保留参数的值,直到执行,就像这些 Stack Overflow 问题中提到的一样。如何在执行前保留setTimeout参数值?并且 for 循环中的 setTimeout 不打印连续值

所以它试了这个

let a = [1,2,3,4,5];

for(let i=0;i<a.length;i++){
  a[i]=7;
  dotimeout(a,i)
}

function dotimeout(a,i){
  setTimeout(function(){
    
    console.log(a)},i*1000)
}

let a = [1,2,3,4,5];

for(let i=0;i<a.length;i++){
  a[i] = 7;
  (
    function(b,j){
      setTimeout(()=>{
        console.log(b);
      },j*1000)
    }(a,i)
  );
}

但两者都给了我相同的结果:

enter image description here

我知道可以在 setTimeout 回调中完成数组操作以达到预期的结果,但这不是我的查询

所以我的问题是:为什么包装 setTimeout( closures,不确定这是否是正确的术语)的函数不起作用,以及如何保留 setTimeout 参数,直到使用 setTimeout 外部的数组操作执行。

JavaScript 数组 循环 闭包 settimeout

评论

1赞 deceze 6/12/2021
只有一个数组对象,它大致在同一时间被记录。除非创建对象的副本,否则它无法记录不同的对象。
1赞 Bhaskar Joshi 6/12/2021
我认为您应该先了解有关事件循环的更多信息。在 for 循环执行完成之前,不会执行 SetTimeout。这就是它打印所有 7 个值的原因。

答:

1赞 obe 6/12/2021 #1

您的循环从头到尾运行。在每次迭代中,它都会将 的元素之一设置为 ,并安排稍后的回调,使用 。a7setTimeout

当回调开始调用时 - 的所有元素都已设置为 。a7

当你作为一个变量传递给你的内部函数时,你实际上传递了一个对它的引用,所以在里面,你的函数仍然可以看到最新的数组。aa

您可以做的一件事是复制并传递:a

let a = [1,2,3,4,5];

for(let i=0;i<a.length;i++){
  a[i] = 7;
  let copyOfA = [ ...a ];
  (
    function(b,j){
      setTimeout(()=>{
        console.log(b);
      },j*1000)
    }(copyOfA,i)
  );
}

虽然使用副本,但内部功能是多余的。这也将起作用:

let a = [1,2,3,4,5];

for(let i=0;i<a.length;i++){
  a[i] = 7;
  let copyOfA = [ ...a ];
  setTimeout(()=>{
    console.log(copyOfA);
  },i*1000)
}
0赞 Yves Ng 6/12/2021 #2

代码没有做错任何错误。解决方案非常简单,只需放入代码块即可。Javascript 有一个叫做 stack 的东西,setTimeout 功能块中的任何事件总是在调用该 setTimeout 的函数的每个事件之后触发,即使超时为 0ms。因此,在进入下一个循环之前,您不会等待任何毫秒的 setTimeout 完成,实际上它只是这样做,然后调用将分配给调用堆栈底部的 which。a[i] = 7setTimeouta[i] = 7dotimeout