Closures are important in JavaScript, but it is important to understand what exactly you are closing
over. To rework your current code (kind of).
function(){
var i;
for(i=0;i<10;i++){
setTimeout(function(){
console.log(i);
}, 1000);
}
}
In this example, your code is basically closing over var i;
, which means that when the timer runs, it will read the value of var i;
and print that out. In this case, as you have seen, when the timer runs, the loop has finished and the value is 10
.
What you want to do is create a new function scope that captures the value of i
at a specific time.
function(){
var i;
for(i=0;i<10;i++){
(function(iInner){
setTimeout(function(){
console.log(iInner);
}, 1000);
})(i);
}
}
This example will create a new anonymous function, and then calling it immediately in the loop, and pass the current value of i
into it, so that when your timer reads iInner
, it will read the value that was passed into the function, rather than the value from var i;
. You can also just call iInner
i
if you want, but I've used two different names for clarity.
There are also helpers that you can use, like .bind
that will essentially automatically create a new anonymous function for you, and pass in arguments like this.
function(){
var i;
for(i=0;i<10;i++){
setTimeout(function(iInner){
console.log(iInner);
}.bind(null, i), 1000);
}
}
<func>.bind
will take the value of i
and return a new function that passes those args through to <func>
when called, and you avoid having to create another layer of nesting.