setTimeout appears to be changing my variables! Why?
The others already wrote the reason for the behaviour you're getting. Now the solution: change the setTimeout
line to:
(function(i) {
setTimeout(function(){console.log(i)}, 1000);
})(i);
This works because it captures the current value of the variable i
into yet another closure, and the variable within that closure doesn't change.
ECMAscript uses the technique of lexical closures
which is nothing else than an internal storage to all parent context objects / lexical environment records (ES3 / ES5).
In short words, your anonymous function used by setTimeout
closes over that i
variable, so while that timeout is "waiting", your loop continues. setTimeout
operatores asynronously of course and that in turn means, at the time that loop has finished the value if i
is of course 2.
Now remember about the closure stuff, our anonymous function in setTimeout
still holds a reference to i
when it finally fires (after 1000ms). So it correctly shows you the value of 2.
If you want to show the numbers for each iteration after 1000ms, you need to invoke another context. This might look similar to
setTimeout((function( local ) {
return function() {
console.log( local );
};
}( i )), 1000);
The for loop continuously increments i
until the loop condition is met, even though the code in the for loop does not execute, when the code in the setTimeout
executes it shows the current value of i
- which is 2
.