Javascript variable scope confusion

Since Javascript has a very C/Java-like syntax, it's easy to make assumptions about the language that turn out to be rather wrong. Take variable scoping for instance. It would seem natural that a variable defined within a loop or within an if conditional, would go out of scope when that loop (or if block) came to an end:


for (var i = 0; i < 100; i++)
{
   var s = 'steve_' + i;
}
alert(s);   // steve_99 or undefined?

Run the above code snippet, and you'll get an alert that says 'steve_99'. It sort of feels like the variable s should be undefined, but it's not. I'm sure there are lots of Javascripters who already know this, but I'm also pretty sure there's also a few who've never noticed this.

Is this always the case? Do all variables created with var end up being essentially global variables? Not exactly.

So in what scenario does variable scoping act that way you'd think it would in Javascript? It's pretty simple actually. All variables created with var are global variables (within their scoped context). Only functions (which in Javascript are objects) and the global object (which in web browsers maps to window) have variable scope. An example will help illustrate:


function foo()
{
   var x = 'llama are so great!';
   alert(x);
}
foo();
alert(x);   // error: x is undefined

This is much more natural and (I think) what most programmers expect. We can combine first example and the second and it should be pretty easy to see what's going to happen.


function foo()
{
   for (var i = 0; i < 100; i++)
   {
      var s = 'steve_' + i;
   }
   alert(s);   // alerts 'steve_99'
   var x = 'llama are so great!';
   alert(x);
}
foo();      // alerts 'steve_99' followed by 'llamas are so great!';
alert(x);   // error: x is undefined

So, as expected, x is still undefined (outside of the function foo()). And s, having been created with var is still "global". Global, that is, in the scope context of the foo() function.

What does this mean for the average Javascipter? Well, it just means you should be careful. Don't be fooled into thinking a variable has gone out of scope, when in fact, it has done no such thing.

Given Javsscript's (somewhat peculiar) handling of variables, you might suggest then, that there is no point in following the typical programming style of declaring variables as close to where they're first used as possible. I know Douglass Crockford believes you shouldn't do this in Javascript. A part of me agrees, but I still tend to do it, just because it helps me, personally, with readability. I can certainly understand the argument though, to do as Mr. Crockford suggests and declare all of your variables at the beginning of your functions.

What's interesting, is that while I haven't really gotten in the habit of doing this, I have gotten into the habit of not declaring looping variables inside of for loops (though admittedly, this is contrary to my above examples). But in most real-world scenarios, I tend to do this:


var i, len = someArray.length;
for (i = 0; i < len; i++)
{
   /* my code here */
}

And not this:


for (var i = 0; i < someArray.length; i++)
{
   /* my code here */
}

I declare the i variable outside of the for loop for just the reasons we've been considering in this post. Since, after the above code executes, i will still be a valid variable with global scope, I prefer to write my code so that it looks that way. It's just too easy to look at the above code snippet and think that i is confined to the scope of the for loop (it's not).

If you don't believe me on this, try running the above code snippet (substitute 100 for someArray.length) and then, outside of the for loop, put the statement alert(i);. You know what you'll get don't you? No, it's not 99. It's 100, which makes perfect sense!

I'm curious to know what other people think about this. I generally don't ask questions in my blog posts (and this probably more to do with the fact that i don't get a ton of traffic (yet) than anything else, but I figure... what the heck, I'll break my normal rules this one time.

What does everyone else prefer and why? What advantages and disadvantages do you see, and what programming notations/styles do you use to help keep variable scoping easily understood and readable in your code?

If you have thoughts on this, I'd love to hear them.

Comments welcome.

4 Responses

  1. Ola Says:

    I have always gone with declaring variables closer to where they are used although I knew that they are in scope for the duration of the function. I think this is because I am coming from a C++ background. Also, the code has less lines when the loop control variables are declared within the context of the loop. I declare them outside the loop if I plan to use them again as it's more readable then. This is assuming that most JavaScripters are coming from a language with C-like syntax so it's more readable to them.

    One last thing, if one thought variables went out of scope when they exit a loop, it would mean they should redeclare the variable with var and then assign it before using it so they still shouldn't have any problems except one regularly pollutes the global namespace without using var.

  2. RichB Says:

    I run JavascriptLint over my code periodically and it picks up on redeclared variables.

    See:
    http://aspadvice.com/blogs/rbirkby/archive/2007/01/22/The-trouble-with-dynamic-languages.aspx

  3. sstchur Says:

    Both RichB and Ola bring up good points, especially the point about redeclared variables. I think this is precisely the main reason the Douglass Crockford suggests declaring all of your variables at the beginning of the function, only one time.

    I can't really argue with that logic; it just makes sense. Maybe I'll have to try to force myself to change my style.

  4. Michael Says:

    I prefer not to declare variables at all to have the code as small as possible

Got something to say?

Please note: Constructive criticism is welcome. Rude or vulgar comments however, are not and will be removed during moderation.