4 ms·
I'm sorry my original post wasn't very clear. My intended point was that if Javascript had true lexical scope then each iteration of the loop would create a di
by KeithMajhor 16y ago
I'm sorry my original post wasn't very clear.
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 )
- udp 16y agoThat was me who mentioned it, actually :-) Yes, I see what you mean now, sorry! 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.
- raganwald 16y ago> You can simulate the behavior of lexical scoping by "abusing" closures as someone mentioned before. 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!
- Cushman 16y agoFor the record, you can also create scope without a closure using with (or let, if it's available.) 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.
- brlewis 16y agoThat isn't lack of lexical scope. It's that the for() syntax isn't purely functional in how it binds variables. One could define an equivalent syntax in Scheme and see the same result. EDIT: http://pastebin.com/7BUXKVXT 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))))
- KeithMajhor 16y agoThis is completely wrong. I don't know what I was thinking. It would be the same variable with or without lexical scope (by that I mean block-level).