3

Possible Duplicate:
setTimeout in a for-loop and pass i as value

for (var i = 0; i < 5; i++) {
    setTimeout(function (i) {
        console.log(this.i)
    }, 1000);
}

This prints 5 five times. How can I write the loop so that it prints 0, 1, 2, 3, 4?

Community
  • 1
  • 1
Vamshi Vangapally
  • 1,972
  • 6
  • 21
  • 25

3 Answers3

7

Wrap it in a self-executing closure:

for (var i = 0; i < 5; i++) (function(i) {
    setTimeout(function() {
        console.log(i)
     }, 1000);
})(i);

Note: the argument to the function-expression to setTimeout is not being used, so I took that out. Also, it's not good to use global variables. Create variables using the var keyword.

You also don't need this.i; simply use i.

David G
  • 94,763
  • 41
  • 167
  • 253
6

Like this:

for (var i = 0; i < 5; i++) {
    (function (i) {
        setTimeout(function () {
            console.log(i)
        }, 1000);
    })(i);
}

The important factor here is that JavaScript only has function scope*, so the only way to create a scope that is different for every loop is to wrap the guts of the loop in a function. That way your setTimeout function creates a closure around i for that iteration of the loop.

EDIT:

* The let keyword is coming in ES6 which gives you the ability to declare a block scope local variable. Chrome 31 does not support it without enabling experimental features so be sure to check compatibility.

Mike Valenty
  • 8,941
  • 2
  • 30
  • 32
  • Now wrong. JavaScript also has block scope for things like catch(), and as of EF6, `let` can be used instead of `var` to give block scope to almost every other kind of block such as `for`s and `if`s. – Jazcash Dec 11 '13 at 13:33
  • Wrong? I would advise against using the `let` keyword in a browser app since it's not yet available in many browsers including Chrome 31 (without enabling experimental flags). Perhaps you can provide more value to the community by posting an answer that uses the `let` keyword and explain the tradeoffs. http://kangax.github.io/es5-compat-table/es6/ – Mike Valenty Dec 11 '13 at 17:22
  • Ignoring `let` for now, there still exists scope within `try`,`catch` like I said. I think this is the only other block that has scope other than `function` in pre-EF6 JS. I'm no JS expert, but your statement 'JavaScript only has function scope' is wrong, albeit very marginally. [Google's Traceur](http://code.google.com/p/traceur-compiler/) provides scope for other blocks in pre-EF6 and it uses `try`,`catch`s to do it. – Jazcash Dec 12 '13 at 09:18
  • Fair enough, I changed the language to not be absolute. – Mike Valenty Dec 13 '13 at 00:06
2

Try this:

var i=0;
var fn;
fn=function(){
      console.log(i)
      i++;
      if(i<=4)setTimeout(fn,1000);
   }
setTimeout(fn,1000);

That will output one number every second five times.

Joshua Dwire
  • 5,415
  • 5
  • 29
  • 50