闭包的意外行为:回调保存最后一个值

时间:2013-09-26 11:57:46

标签: javascript closures bind

我会明白:我有这个循环:

for (var i = 1; i <= toSchedule; i++) {
        when = trackWrapper.lastPlay +
                (trackDuration +
                (looper.timeInterval - trackDuration));

        track.play(true, when);
        trackWrapper.lastPlay = when;
    }

play方法在体内有这个:

[...]
// Here when is a different value for each call (verified)
// Many calls of the play method are performed before the returned function below is run as a callback
        function playingCallback(myWhen){

            return function(buffers){
                // Here myWhen will always be equal to the value of the last call occurred BEFORE the first callback execution
                console.log("myWhen = "+myWhen);
                [...]

            };
        };

        var realCallback = playingCallback(when);

        track.scheduled.push(when);
        track.recorder.getBuffer(realCallback);

所以,例如:

play(true, 1);
play(true, 2);
play(true, 3);

// Wait for it...

myWhen = 3;
myWhen = 3;
myWhen = 3;

现在:我已经阅读了关于闭包的内容,我已经读过“臭名昭​​着的循环问题”,我在StackOverflow上已经阅读了数十个答案,但我无法弄清楚这一点。这是我第二次遇到回调问题,所以在这一点上,我想我还没有完全理解发生了什么。

请您解释一下上面的代码应该是什么问题?提前谢谢。

1 个答案:

答案 0 :(得分:1)

通常,您应该了解以下规则:即使在退出范围之后,clousure也可以访问其“周围范围”。但它将是执行时范围的状态,而不是(!)在关闭的创建时间

如果在循环内创建闭包,它将可以访问循环变量。但循环很可能已经结束。所以循环变量将保持其最后一个循环的值。

因此,如果您的闭包是一个回调,您应该在创建时创建相关范围变量的副本,并在执行时使用此副本。您可以通过从立即执行的匿名函数

创建内部闭包来执行此操作(例如)
function myOuterScope(count) {
   for(i=0; i<count; i++) {
      setTimeout((function(local_i) {
         // this function will be immediately executed. local_i is a copy of i at creation time
         return function() {
            // this is the function that will be called as a callback to setTimeout
            // use local_i here, and it will be 0, 1, 2 instead of 3, 3, 3
         }
      })(i)
      , 1000);
   }
}
myOuterScope(3);