Basic JavaScript Part 5: Hoisting

December 24th, 2010

Here are the links to the previous installments:

  1. Functions
  2. Objects
  3. Prototypes
  4. Enforcing New on Constructor Functions
    I just wanted to quickly share a little tidbit that I ran into the other day while I was messing with JavaScript again. Try to guess what the output is going to be when running the following code snippet:
    var num = 56;
    function calculateSomething() {
        console.log(num);    
        var num = 12;
        console.log(num);    
    }
    
    calculateSomething();
    Without further ado, this is the output shown in the console window:

image

    I must admit that this had me beat the first time I saw this, but it really makes perfect sense.
    JavaScript doesn’t support block scope but instead it makes use of function scope. Block scope means that variables declared in a block are not visible to code outside that block. We all know that the following C#code doesn’t compile for exactly that reason:
    public void Stuff()
    {
        {
            var i = 2;
        }
    
        // Compiler error: The name 'i' does not exist in the current context.
        Console.WriteLine(i);    
    }

But function scope means that all variables and parameters declared inside a function are visible everywhere within that function, even before the variable has been declared. This is the behavior that we see by running the code snippet shown earlier.

    Just as with C#, we can put a variable declaration anywhere in our JavaScript function as we did earlier. In that case, JavaScript will just act as if the variable has been declared at the top of the function. This behavior is called hoisting. This means that it is valid to use this variable as long as it has been declared somewhere within the function. Going back to our previous sample, the net result is that JavaScript will interpret the function as something like this:
    var num = 56;
    function calculateSomething() {
        var num;            // undefined
        console.log(num);    // outputs 'undefined'    
        num = 12;            // 12
        console.log(num);    // outputs '12'    
    }
    
    calculateSomething();

    Now I know why Douglas Crockford advised in his book JavaScript – The Good Parts to declare all variables at the top of the function body. In order to prevent nasty side-effects like this to happen, I think it’s best taking up on that advice.

    Till next time.

  • Jon

    Thanks for the great series; it has been enough to jumpstart me on the language, so I can’t thank you enough.

    Jon

  • http://elegantcode.com/ Jan Van Ryswyck

    @Jon
    Thank you for the kind words. I hope you enjoy using this great programming language as much as I do.

  • http://bateru.com Larry Battle

    Using a Singleton pattern for global variables would have avoided this problem.
    Thanks for the lesson because it tricked me this first I looked at it.

  • http://droope.wordpress.com droope

    That’s weird! Supossedly, variables declared outside all functions are considered global and are available between functions.

    Are you sure that you aren’t caught inside a $(document).ready)() {}?

  • drew

    This is the most common problem I see in code. In fact I don’t recall a large JavaScript application that declared all variables at the top of the function. I even had a colleague that posted refactoring this was disruptive ….

  • drew

    This is the most common problem I see in code. In fact I don’t recall a large JavaScript application that declared all variables at the top of the function. I even had a colleague that posted refactoring this was disruptive ….

  • http://droope.wordpress.com droope

    Ah!!

    try removing line 3.

  • El Guapo

    I’ve commented before about what a terrible language Javascript is, and this is another great “feature”. It’s even more so a trap due to the fact that the specification is so ambiguous, you don’t really know how a given runtime will implement it. If you read about hoisting, the first function should logically report 12, as the var num gets moved to the function top at parse time. However, you demonstrate it does otherwise, for this particular runtime. Even more so is you could also expect the global num to take effect, then be masked by the local( although if hoisting is implemented as described, it would be masked by the local).

    Don’t get me wrong, I don’t hate Javascript for the sake of hating. Its a non-entity with no will of its own after all. What I hate is that it became the lingua franca of the web, that so much effort continues to be expended on it, and that it never matured or stabilized as a language. The “specification” is a joke, the language is buggy and naive in implementation, and it continues to waste programmer time on a grand scale. That’s not hate, its objective reason getting irritated. :-)

  • http://twitter.com/droope123 Pedro

    javascript ftw

  • doom 95

    I presume you don’t have PHP in much higher regard, huh? I sympathize with web developers. What a hell-hole.