为什么setTimeout回调中的变量没有预期值?

时间:2011-08-27 09:02:20

标签: javascript

<div id="image_cont">
  <img src="images/pic1.jpg" alt="pic1" />
  <img src="images/pic2.jpg" alt="pic2" />
  <img src="images/pic3.jpg" alt="pic3" />
</div>

$(document).ready(function() {
    slide(3, "image_cont", 5000, 600);
});

function slide(numberOfImages, containerId, timeDelay, pixels) {
    //start on first image
    var i = 0;
    var style = document.getElementById(containerId).style;
    window.setInterval(function() {
        if (i >= numberOfImages){
            i = 0;
        }
        var marginLeft = (-600 * i);
        var pixelMovement = pixels/15;


////////////////////////////////////////LOOK HERE//////////////////////////////


        for (var j = 0; j * pixelMovement < 600; j++){
            window.setTimeout(function(){
//alert('marginLeft: ' + marginLeft + ' j: ' + j + ' pixelMovement: ' + pixelMovement);
//this alert shows j is 15 when it should be 0, what's going on?


/////////////////////////////////////////END//////////////////////////////////
                style.marginLeft = (marginLeft - j * pixelMovement) + "px";
                }, 150);
        }
        i++;
    }, timeDelay);
}

3 个答案:

答案 0 :(得分:5)

你不能直接在setTimeout函数中使用变量j,因为该函数在for循环完成后运行一段时间,因此j具有终止值,而不是调用setTimeout时的值。 / p>

您可以在setTimeout函数中捕获函数闭包中的j的当前值,如下所示:

for (var j = 0; j * pixelMovement < 600; j++){
    window.setTimeout(function(cntr) {
        return function() {
            style.marginLeft = (marginLeft - cntr * pixelMovement) + "px";
        };
    } (j), 150);
}

我发现这种类型的封闭令人困惑。我会试着解释发生了什么。我们传递给setTImeout()函数执行一个带有一个参数的匿名函数(我在这里命名为cntr)的结果,并传递j的值作为该参数的值。当该函数执行时(现在其中有j的值可用),该函数返回另一个匿名函数。另一个匿名函数是setTimeout在触发时实际调用的函数。但是,第二个匿名函数位于第一个函数的函数闭包内,其中包含捕获的j值(作为我在函数闭包内重命名为cntr的变量,以避免在解释时出现混淆它)。这是匿名函数,使它如此混乱,但它的工作原理。

答案 1 :(得分:1)

它应该是任何东西,因为window.setTimeout是一个“异步”函数,所以它在执行后立即返回。

所以在你的代码中for循环保持循环,一段时间(150ms)后你的函数被执行,j变量的实际值被打印出来。

答案 2 :(得分:0)

您创建并传递给setTimeout的函数都引用相同的循环计数器变量j - 在循环运行之后,j将被设置为导致的值要终止的循环。您需要使用闭包来确保您在内循环中创建的函数可以访问定义函数时的值j

有关问题和解决方案的更多详细信息,请参阅此答案:

(愚蠢的变量名称,以明确它与j不同):

window.setTimeout((function(jWhenFunctionWasDefined) {
  return function() {
    style.marginLeft = (marginLeft - jWhenFunctionWasDefined * pixelMovement) + "px";
  }
})(j), 150)