Javascript:给数组中的每个对象一个方法上的setInterval

Javascript:给数组中的每个对象一个方法上的setInterval,javascript,Javascript,javascript的新特性 我有一个自定义的对象和一个方法更新。我有一个对象数组 function update_all(objects){ for (var i = 0 ; i < objects.length; i++){ var obj = objects[i]; var repeater = setInterval(function () {obj.update();}, 1000); } } 函数更新\u所有(对象){ 对于

javascript的新特性

我有一个自定义的对象和一个方法更新。我有一个对象数组

  function update_all(objects){
    for (var i = 0 ; i < objects.length; i++){
       var obj = objects[i];
       var repeater = setInterval(function () {obj.update();}, 1000);
    }
  }
函数更新\u所有(对象){
对于(var i=0;i
奇怪的是,只有数组的最后一个对象才能获得objects update方法的setinterval。此外,所有设置间隔都指向数组的最后一个对象。例如,如果有4个对象,最后一个对象每秒更新4次,其他对象则根本不更新。发生什么事了


感谢JavaScript中的for循环不会为变量打开新的作用域。您的
obj
变量至少具有函数作用域(如果您的代码在函数中,或者全局作用域中)。也就是说,通过for循环的每次迭代实际上都会更改函数中单个
obj
变量的值。当您离开for循环时,最终会有很多计时器,但它们都在同一个对象上调用update

为了避免这种情况,您需要将循环体提取到另一个函数中,以便为每个迭代创建一个新的范围。除了一些其他建议外,它可能看起来像这样:

var i, n;

for (i = 0, n = objects.length; i < n; i++) {
    createIntervalToCallUpdate(objects[i]);
}
为了更好地理解这一点,请阅读一个叫做“提升”的概念,例如本文。提升也是许多人建议在函数顶部声明所有变量的原因。如果您在函数的顶部声明了
obj
(这意味着,在for循环之外),您就不会相信变量可以为每次迭代重新定义


更新:Philipp的建议很好,因为它使代码更简单,更易于阅读(考虑到您的浏览器支持较新的
array.forEach
)。它基本上与上面的代码完全相同,只是它已经为您完成了第一个代码段的任务。

在JavaScript中,for循环不会为变量打开新的作用域。您的
obj
变量至少具有函数作用域(如果您的代码在函数中,或者全局作用域中)。也就是说,通过for循环的每次迭代实际上都会更改函数中单个
obj
变量的值。当您离开for循环时,最终会有很多计时器,但它们都在同一个对象上调用update

为了避免这种情况,您需要将循环体提取到另一个函数中,以便为每个迭代创建一个新的范围。除了一些其他建议外,它可能看起来像这样:

var i, n;

for (i = 0, n = objects.length; i < n; i++) {
    createIntervalToCallUpdate(objects[i]);
}
为了更好地理解这一点,请阅读一个叫做“提升”的概念,例如本文。提升也是许多人建议在函数顶部声明所有变量的原因。如果您在函数的顶部声明了
obj
(这意味着,在for循环之外),您就不会相信变量可以为每次迭代重新定义


更新:Philipp的建议很好,因为它使代码更简单,更易于阅读(考虑到您的浏览器支持较新的
array.forEach
)。它基本上与上面的代码完全相同,只是它已经为您完成了第一个代码段的任务。

变量
obj
对所有迭代都具有相同的作用域。您可以通过将for循环替换为函数来解决该问题

 objects.forEach( function(obj) {
      setInterval(function () {obj.update();}, 1000);
 });

forEach函数为数组中的每个条目调用声明的函数一次。匿名函数定义了一个闭包,其中每个
obj
代表一个不同的实例。

变量
obj
对所有迭代都具有相同的作用域。您可以通过将for循环替换为函数来解决该问题

 objects.forEach( function(obj) {
      setInterval(function () {obj.update();}, 1000);
 });

forEach函数为数组中的每个条目调用声明的函数一次。匿名函数定义了一个闭包,其中每个
obj
代表一个不同的实例。

您所经历的与闭包有关。变量
obj
不仅可在
for
-循环中访问,这意味着当执行
setInterval
的回调时,它将是可用的
obj
的最后一个引用-在本例中是数组中的最后一个对象

要解决此问题,可以尝试将内置函数
forEach
与用于设置间隔的函数结合使用:

function setObjectInterval( obj ) {
    setInterval(function () {obj.update();}, 1000);
}

objects.forEach( function( obj ) {
    setObjectInterval( obj );
} );

您所经历的与闭包有关。变量
obj
不仅可在
for
-循环中访问,这意味着当执行
setInterval
的回调时,它将是可用的
obj
的最后一个引用-在本例中是数组中的最后一个对象

要解决此问题,可以尝试将内置函数
forEach
与用于设置间隔的函数结合使用:

function setObjectInterval( obj ) {
    setInterval(function () {obj.update();}, 1000);
}

objects.forEach( function( obj ) {
    setObjectInterval( obj );
} );

仅供参考,在循环之前计算
对象的速度更快,因为如果在循环创建期间调用,每次迭代都会重新计算
的长度。您必须使用闭包将数据传递给内部函数,在@Grim处演示。。。不,不是这样。@Benjamin,也许Grim的语句可以这样重新表述,以防止出现争论:“…
对象。循环前的长度,因为它可能会根据JavaScript解释器在每次迭代中进行计算”@chiccodoro是的,我想可能会,但它确实不会,保证。从技术上讲,interperter可以在每次访问对象长度时执行
线程。Sleep(1000)
,但没有一个可以。缓存
array.length
在过去几年的任何JavaScript interperter中都没有更快,它只是增加了混乱。另一方面,缓存DOM
NodeList
s的长度很重要(这是一个相当常见的误解),因为
NodeList
s是活动的-这意味着如果