0

How do I set 'i' in the function below to be incremental inside the setInterval rather than reading the final value of 'i' ?

    window.onload= function(){
        var res = ['a','b','c']
        for(i=0;i<res.length;i++){
            document.body.innerHTML += "<li id='L"+i+"' style='display:none;'>"+res[i]+"</li>";
            setTimeout(function(){ 
                document.body.innerHTML += 'L'+i+'<br/>';
                document.getElementById('L'+i).style.display = 'block'
            },1000+i*50);
        }
    }

outputs:

L3
L3
L3
cronoklee
  • 6,482
  • 9
  • 52
  • 80
  • https://developer.mozilla.org/en/JavaScript/Guide/Closures – Andreas Louv Jul 09 '12 at 08:36
  • possible duplicate of [Javascript closure inside loops - simple practical example](http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example) – Felix Kling Jul 09 '12 at 08:39

2 Answers2

2

For loops (or any blocks for that matter) don't provide a new scope for free like in other languages, you must either use an inline closure or use functional iteration with .forEach where you get the inline closure as a "side effect":

window.onload= function(){
    ['a','b','c'].forEach( function(letter, index) {
        document.body.innerHTML += "<li id='L"+index+"' style='display:none;'>"+letter+"</li>";
        setTimeout(function(){ 
            document.body.innerHTML += 'L'+index+'<br/>';
            document.getElementById('L'+index).style.display = 'block';
        },1000+index*50);
    });
}

If required, use the shim here for older browser support:

https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/forEach

Esailija
  • 138,174
  • 23
  • 272
  • 326
  • 2
    @AndreasAL you should not downvote because of that. Nowhere was there a requirement for older browser stated. Especially when I was just about to edit in the explanation – Esailija Jul 09 '12 at 08:37
  • I have removed my downvote. As I now see you have explained this. Good... But don't you think its a better approach telling cronoklee about closures instead of just giving hem a new solution witch dosn't make hem a more skilled programmer? – Andreas Louv Jul 09 '12 at 08:41
  • Thanks to all for the tips on this - never heard of a closure - seems to be automatic in other languages. Will read up on it. Cheers – cronoklee Jul 09 '12 at 08:57
1

This is because when your callback executes, the variable i is 3, you could do it like below:

    setTimeout((function(i){
      return function() {
        document.body.innerHTML += 'L'+i+'<br/>';
        document.getElementById('L'+i).style.display = 'block';
      };
    })(i), 1000+i*50);
xdazz
  • 158,678
  • 38
  • 247
  • 274
  • The `setTimeout` callback *is* already a closure (otherwise it could not access `i`). What you added is a self-executing function to create a new scope which is, strictly speaking, not a closure. – Felix Kling Jul 09 '12 at 08:40
  • 1
    @FelixKling Can we say that the parameter variable `i` is in the closure? – xdazz Jul 09 '12 at 08:42
  • I'm not sure what you mean... the function returned from that self-invoking function is a closure since it closes over `i`. – Felix Kling Jul 09 '12 at 08:43
  • 1
    @Andreas: This edit was irrelevant and tools like JSLint and JSHint actually prefer the calling parenthesis after `}`. – Felix Kling Jul 09 '12 at 08:45
  • @FelixKling What my understanding for closure is a closed scope, in this case, the `i` is in the closed scope, so I said it is a closure. – xdazz Jul 09 '12 at 08:47
  • No, a closure is a function which has access to variables defined in a higher execution context, if this context does not exist anymore. So for example, functions returned by other functions, callbacks (most of the time) and event handlers are all closures. In a less strict view, you could say that any function that has access to higher scope variables is a closure, I'm a bit unsure here. Wikipedia is probably more precise than me ;) http://en.wikipedia.org/wiki/Closure_%28computer_science%29 – Felix Kling Jul 09 '12 at 08:49
  • *a closure is a function together with a referencing environment for the non-local variables of that function.* Though I like to misuse this term a lot – Esailija Jul 09 '12 at 08:49
  • @FelixKling I'm a bit confused, in this case, isn't the `i` in higher execution context, why this is not a closure? – xdazz Jul 09 '12 at 08:53
  • As I said, the function you *return* from the self-invoking function is a closure. The immediate function (`(function(i){...}(i))`) is not (or at least you are not using it as such), since you are *passing* `i` as argument to the function. But no matter whether it is a closure or not, the phrase *"you need to use a closure"* is not correct as is, since the original callback the OP passed is a closure as well, so you are telling the OP to use something that he is already using... the important point of your answer is that you are *calling* a function to create a new scope. – Felix Kling Jul 09 '12 at 08:58
  • @FelixKling Now I understood what you mean, thank you very much! – xdazz Jul 09 '12 at 09:00