Tales from the Evil Empire

Bertrand Le Roy's blog

News


Bertrand Le Roy


Add to Technorati Favorites Tales from the Evil Empire - Blogged

Blogs I read

My other stuff

Archives

More weird JavaScript: variable scope

I know I'm going to get "only a n00b would not know that" comments, but I'm sure this will help some folks out there, so here it goes.

Eilon pointed out to me this morning this weird and very counter-intuitive behavior of JavaScript. Basically, there is no block scope for variables...

var x=1;
if (true) {
    var x=2;
    if (true) {
        var x=3;
        alert(x);
    }
    alert(x);
}
alert(x);

outputs 3 three times, whereas in all other curly brace languages that I know, you'd get 3, 2 and 1.

Except that there is variable scope... Only in functions and script blocks. That's what enables OO programming using closures.

To summarize: variables in JavaScript are only local to functions, not to any other kind of {} block.

If anybody has a good explanation for why JavaScript goes against all tradition from its ancestor language (C), I'd be genuinely interested in knowing it.

(thanks to David and Karsten for some insights on this issue)

Comments

Alan Oursland said:

I think this is especially error prone since it lets you put the var keyword in front of each "declaration". I don't know really know the full semantics of "var". I know that it declares a symbol to be a variable and that it is optional, but it seems like it might be useful for it to give some warning if you use it on a symbol more than once.

Python uses the same scoping rules as JavaScript. It might have something to do with syntax associated with weak typing. Because you do not actually have to declare variables, there isn't a good way to tell when you want a new variable or reuse an old variable. So you have to attach the scoping rules exclusively to code blocks.
# February 24, 2006 3:41 PM

Bertrand Le Roy said:

If you turn on strict mode in Firefox (which I recommend to all JS developers out there), you do get a warning for multiple declarations.
I think you're right. I'm also suspecting that it has to do with the very nature of dynamic languages but the exact precise reason why they could do it for function blocks and not other kinds of blocks eludes me.
# February 24, 2006 3:44 PM

Edgardo said:

Ehm, where is the weirdness in this? C# works exactly the same, nested if blocks use the same scope.
# February 24, 2006 7:01 PM

Bertrand Le Roy said:

Actually, C# won't let you compile that. BUT a variable is not accessible outside of its scope. This:
{
int x = 1;
Response.Write(x);
}
Response.Write(x);
will not compile, whereas JavaScript would be perfectly happy with it and write 1 twice.
# February 24, 2006 7:25 PM

James Newton-King said:

I have been bitten a number of times using "i" in nested for loops without realising it. The inner loop overwrites the value of the outer loop.
# February 24, 2006 7:29 PM

Brian said:

Here is another weird thing:

function what()
{
for(x=0;x<5;x++)
{
alert(x);
t();
alert(x);
}
}

function t()
{
x = 12;
}

In IE I know you you'll get "alert(0)" then "alert(12)" and it will exit your function.
I have run across this a couple times when I have a function that is calling another function that uses the same variable without the "var x;".

That has bit me in the butt a couple of times, if you don't "declare" your variables.
# February 24, 2006 8:06 PM

Bertrand Le Roy said:

Brian: I don''t think this one is especially weird. It *is* a bug factory, yes, but you need a way to reference global variables so this is more or less needed.
If you run this in Firefox in script mode, it will issue a warning for the use of an undeclared variable, which really helps avoiding this kind of problem.
# February 24, 2006 8:10 PM

Scott said:

Bertrand,

Execution scope in Javascript is pretty hard to get used to. Especially when using the 'this' keyword. I've got a couple of links that saved me from having to read teh ECMA spec.

Private members in Javscript: http://www.crockford.com/javascript/private.html

Closures in Javascript: Explains execution scope and how closures work. http://jibbering.com/faq/faq_notes/closures.html

Javascript closures took me a long time to understand, I'm still not sure I really understand how they work. But I'm getting closer to understanding.
# February 25, 2006 12:25 AM

Steve said:

More good reason to have a client side version of C#.... :)
# February 26, 2006 12:06 PM

Jb Evain said:

Hey Bertrand,

I've just learned how blocks can be simulated in JavaScript:

var x = 1;
if (true) {
____(function () {
____var x = 2;
____if (true) {
________(function () {
____________var x = 3;
____________alert (x);
________}) ();
____}
____alert (x);
____}) ();
}
alert (x);

Well, it's a trick :)

(From: http://www.application-servers.com/links.do?reqCode=showLink&lid=3092 )
# March 10, 2006 12:21 AM

Bertrand Le Roy said:

JB: I think we read the same blogs ;) . I've seen this one. The problem with it is that it uses nested closures. I'm fine with closures when used reasonably, but this one for me is too much. I think it's not very readable, it has all the dangers of closures and it's just not worth the trouble.
I think it's best just to be conscious of this problem and deal with it without hacking around it.
# March 10, 2006 1:08 PM

Lonnie Best said:

Leave off the var operator and you will have your global scope. Don't var unless you want the variable to be local in scope.
# August 28, 2006 3:06 PM

Bertrand Le Roy said:

Lonnie: if you do that, you'll get warnings from Firefox in strict mode. If you want global scope, you can use expandos off window. Unfortunately, EcmaScript doesn't standardize on a consistent global object, so this won't work in other hosts than browsers.

# August 28, 2006 3:58 PM