Reputation: 8718
I hit a subtle bug which has been distilled as follows:
function huh() {
for (var i = 0; i < 10; i++) {
if ( i % 2 == 1 ) {
var x = i;
console.log(i + ' ' + x);
}
else {
console.log(i + ' ' + x);
}
}
}
huh();
Firstly, I would challenge even experienced JavaScript programmers to correctly predict the exact output of this program on paper only. But mainly, JavaScript seems to be mixing dynamic and lexical scoping. And it seems there is no block scope, only function scope, which is basically blowing away my whole concept of scoping in JavaScript. Can someone explain in reference to the standard, and maybe a bit of rationale? This seems highly counter-intuitive.
Upvotes: 1
Views: 178
Reputation:
There is block scoping in JavaScript from ecmascript version 6 with the let
keyword.
That aside, the way it works with the var
statement is that the statement floats to the top of the function before the function is being executed. Variable declarations take place before anything else, regardless of the blocks they are in, including inside for loop statements. The actual assignments of the variables does happen in place, so they are undefined but not undeclared until the line of code where they get assigned something.
As for your specific example, remember that primitive values like numbers are not assigned by reference but by value, and that the updating of x
will only happen on uneven numbers and will be undefined the first time round, but if it would be objects, they would refer to the same object once you assigned one to the other (regardless of if/else conditions).
To provide further confusion, note that console in browsers is asynchronous, so you could print objects to the console (not primitives though) and inspect them where you would not get the state of the object at the time of the console.log
statement, but at a later time. That's very confusing for debugging.
Yes JavaScript in practice definitely has a bit of a learning curve.
Upvotes: 1
Reputation: 6051
This somewhat puzzling effect is a combination of function scope and variable hoisting.
You should consider the above code equivalent to:
function huh() {
var i, x;
for (i = 0; i < 10; i++) {
if ( i % 2 == 1 ) {
x = i;
console.log(i + ' ' + x);
}
else {
console.log(i + ' ' + x); }
}
}
Upvotes: 1