My intended point was that if Javascript had true lexical scope then each iteration of the loop would create a distinct variable. A reference to that variable would then be captured by each closure. You can simulate the behavior of lexical scoping by "abusing" closures as someone mentioned before. Like this:
for ( var i = 1; i < 10; ++i ) ( function( i ) { setTimeout( function( ) { alert( i ) }, i * 250 ) } )( i )
I wonder about the word "abusing" here. Languages that have block-level lexical scoping (I hope I am using the correct word) sometimes implement block scoping by renaming the variables and hoisting them to the enclosing function, and they sometimes implement block scoping by creating a new closure just as we do by hand in JavaScript, and then hoisting the result.
For example, naïve implementations of Scheme give you a "let" macro that is expanded into the closure form you give above, and then an optimizing step comes along a little later and performs lambda hoisting for you. So this "abusing" we are doing is what the language would have done for us in certain implementations anyways!
for (var i = 1; i < 10; ++i)
{
with({i:i}) // let (i=i)
{
setTimeout( function( ) { alert( i ) }, i * 250 );
}
}
will do what you intend. If let is available, for (let i = 1; etc. will do the same thing without the cruft.EDIT: http://pastebin.com/7BUXKVXT
Paste it into Racket and choose language R5RS.
(define-syntax for
(syntax-rules ()
((for ((var init) condition step) expr ...)
(let ((var init))
(let loop ()
(if condition
(begin
(begin expr ...)
step
(loop))))))))
(define (test-for)
(let ((v (make-vector 10)))
(for ((i 0) (< i 10) (set! i (+ 1 i)))
(vector-set! v i (lambda () i)))
(for ((i 0) (< i 10) (set! i (+ 1 i)))
(display ((vector-ref v i)))
(newline))))This reminds me of bug in the Visual C++ 6.0 compiler, where a variable declared in the "head" of a for loop would continue to exist after the loop scope had closed. Javascript has exactly the same problem, but by design, due to only having global and function-level scope.
It would be the same variable with or without lexical scope (by that I mean block-level).