jquery回调函数仅适用于最后一个循环

for(var i=0; i<barValues.length; i++) { actualBarHeight = Math.floor((barValues[i]/chartMaxY)*barchartHeight); var barChartID = "#barChart" + (i+1) $(barChartID + " .value span").css('background-color','transparent'); $(barChartID + " img").animate({ height: actualBarHeight }, 500, function(){$(barChartID + " .value span").css('background-color','white');} ); $(barChartID + " .value span").html("$"+Math.floor(barValues[i])); $(barChartID + " .value").css("bottom",actualBarHeight+"px"); $(barChartID + " .ylabel").html(chartMaxY); }; 

上面的jQuery位于for循环中。 循环的每次迭代执行以下操作:

  • 设置跨度的背景
  • 动画一个对象
  • 完成后,重置跨度的背景

我正在使用回调函数来重置背景,因此在完成动画之前完成动画。 但是,它最终只会影响for循环中引用的最后一个span。

如果我在回调之外移动那段代码,那么它会在for循环的每次迭代中影响每一个跨度(但在这种情况下不等待动画)

我猜这个问题与构建选择器INSIDE函数INSIDE animate函数有关。 我的标记中有一些错误的语法吗?

编辑(根据Russ的建议,我现在包括上面示例中的完整循环)

这是将闭包与循环组合时遇到的常见问题。 JavaScript是一种后期绑定语言,循环不会引入新的范围。 所以:

 for (var i= 0; i<5; i++) { $('#thing'+i).click(function() { alert(i); }); } 

此代码中只有一个i变量。 它从0开始,一旦完成赋值循环,则保持为5#thing0元素上的click事件只有在循环执行完毕才会被触发,此时i的值将为5 。 您将无法获得您可能期望的define-time值0

这不仅适用于循环变量本身,也适用于每次循环时重新分配的任何其他变量。 因此,在您的示例中,动画回调函数中barChartID的值将始终是与循环中最后一个元素关联的id。

通常的解决方法是通过使用引入新范围的结构(即另一个函数)在define-time获取循环变量值的副本:

 $(barChartID + " img").animate({height: actualBarHeight}, 500, function(barChartID) { return function() { $(barChartID + " .value span").css('background-color','white'); }; }(barChartID)); 

关于循环闭合的更多信息。

这是因为你的回调函数有一个指向barChartID变量的隐式指针。 这就是闭包的工作原理。 你想要的是在每次迭代中创建barChartID的当前值的新副本。 解决此问题的一种模式是在函数内运行for循环的主体。 我看到了这种模式,除了John Resig 关于JavaScript忍者的秘密书“ Secrets”

 for(var i=0; i 

由于您使用的是jQuery,因此可以使用$ .each函数而不是for循环。 用于代替循环的回调将创建一个新的闭包。

 $.each(barValues, function(i, barValue){ actualBarHeight = Math.floor((barValue/chartMaxY)*barchartHeight); var barChartID = "#barChart" + (i+1) $(barChartID + " .value span").css('background-color','transparent'); $(barChartID + " img").animate({ height: actualBarHeight }, 500, function(){$(barChartID + " .value span").css('background-color','white');} ); $(barChartID + " .value span").html("$"+Math.floor(barValue)); $(barChartID + " .value").css("bottom",actualBarHeight+"px"); $(barChartID + " .ylabel").html(chartMaxY); }); 

您可以尝试缓存span选择器,如下所示:

 var barChartID = "#barChart" + (i+1) var span = $(barChartID + " .value span"); span.css('background-color','transparent'); $(barChartID + " img").animate({ height: actualBarHeight }, 500, function() { span.css('background-color','white'); });