Javascript闭包";商店“;价值在错误的时间

Javascript闭包";商店“;价值在错误的时间,javascript,closures,Javascript,Closures,我正试着逐渐增加反作用力。以下工作: function _award(points){ var step = 1; while(points){ var diff = Math.ceil(points / 10); setTimeout( "_change_score_by("+diff+");" /* sigh */, step * 25); points -= diff; step++; } } 但是,它使

我正试着逐渐增加反作用力。以下工作:

function _award(points){    
  var step = 1;
  while(points){
    var diff = Math.ceil(points / 10);
    setTimeout( "_change_score_by("+diff+");" /* sigh */,
                step * 25);
    points -= diff;
    step++;
  }
}
但是,它使用隐式eval。邪恶!让我们用闭包代替,对吗

function _award(points){    
  var step = 1;
  while(points){
    var diff = Math.ceil(points / 10);
    setTimeout( function(){ _change_score_by(diff); },
                step * 25);
    points -= diff;
    step++;
  }
}
显然,这是行不通的。创建的所有闭包捕获函数--1中的最后一个值
diff
。因此,所有匿名函数将使计数器增加1,例如,
\u award(100)
将使分数增加28


如何正确地执行此操作?

这是一个已知的问题。但您可以轻松地在每个循环迭代中创建一个闭包:

(function(current_diff) {
    setTimeout(function() {_change_score_by(current_diff);},
               step * 25);
})(diff);
很有效(谢谢!),但就我个人而言,我更喜欢将其更改为更明确的方式:

function _schedule_score_change(diff, step){
  setTimeout( function(){ _change_score_by(diff) },
              step*25 );
}

function _award(points){    
  var step = 1;
  while(points){
    var diff = Math.ceil(points / 10);
    _schedule_score_change(diff, step);
    points -= diff;
    step++;
  }
}

使用ECMAScript第五版的
函数#bind
方法,解决闭包循环问题变得不那么麻烦:

setTimeout(_change_score_by.bind(window, diff), step*25);

现在,您可以进入不支持Functional.js的浏览器以获得好处。

使用Functional.js,您可以创建传递给
setTimeout()
的函数,如下所示:
\u change\u score\u by.saturate(diff)
并且您不需要匿名函数。我猜您还必须将
步骤作为参数传递?@badp No.setTimeout(param1,param2)此时执行。只有函数param1的“内部”没有被计算(正如您在文章中所指出的,它将在稍后执行)。我不会把这称为“问题”。这只是Javascript中定义词法范围的方式。@Pointy Feature,然后:)只是每个js程序员可能都犯过一次这个错误。(至少是这样)