Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does variable in setTimeout callback not have expected value?

Tags:

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);
}
like image 436
deadghost Avatar asked Dec 12 '25 06:12

deadghost


1 Answers

You can't use the variable j directly in the setTimeout function because that function runs some time later after your for loop has completed and thus j has the terminating value, not the value when you called setTimeout.

You can capture the current value of j in a function closure that would be available in the setTimeout function like this:

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

I find this type of closure kind of confusing. I'll try to explain what's happening. We pass to the setTImeout() function the result of executing an anonymous function that takes one parameter (which I named cntr here) and we pass the value of j as the value of that parameter. When that function executes (which now has the value of j available inside it), that function returns another anonymous function. This other anonymous function is what setTimeout will actually call when it fires. But, this second anonymous function is inside a function closure from the first function that has the captured value of j in it (as a variable that I renamed cntr while inside the function closure to avoid confusion in explaining it). It's the anonymous functions that make it so confusing, but it works.

like image 79
jfriend00 Avatar answered Dec 14 '25 19:12

jfriend00



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!