Javascript: the Scope Pitfall II

Hello, and welcome to the second part of “Javascript: The Scope Pitfall”. Let’s get started, shall we?

What does the following code print?

var n = 0;
function add() {
    var m = n + 1;
    print(m);
}
add();

That was easy, right? The answer, of course is 1, because 0 + 1 == 1. Alright, a slight variation on the same example:

var n = 0;
function add2() {
    var n = n + 1;
    print(n);
}
add2();

What does this print? If your answer is NaN (not a number), you can stop reading. If you think the answer is 1 (as I did), read on. What is happening here? In my previous post I explained that Javascript lifts variable declarations to the top of the function. So, this code is equivalent to:

var n = 0;
function add2() {
    var n;
    n = n + 1;
    print(n);
}
add2();

It also turns out that when a previously undeclared variable (in this scope) is declared it is initialized to undefined. So we get:

var n = 0;
function add2() {
    var n = undefined;
    n = n + 1;
    print(n);
}
add2();

Any calculation involving undefined will return NaN, so naturally it will indeed print NaN. You can rewrite the code a little bit to make it print 1 again:

var n = 0;
var oldN = n;
function add3() {
    var n = oldN + 1;
    print(n);
}
add3();

It took me a while to figure this one out, though, when I ran into it. Just thought I would share.

Got something to say?
  1. I was watching http://channel9.msdn.com/posts/Charles/Introduc… and it seems there's a scope bug in IE:

    function test() {
    var x = 3;
    try { throw 5; }
    catch (x) {}
    alert(x);
    }

    The output should be 3, but in IE it's 5. Apparently the scope rules are giving the IE team a hard time. :p

  2. justinjohnsonorg says:

    That's disappointing. Any version of IE in particular?

  3. MrColes says:

    Nice clean example! I figured I’d add a variation of your example that highlights the case of javascript lifting variable declarations to the top of a function:

    var x=0;
    function add() {
    x = x + 1;
    if (false) { var x; }
    return x;
    }
    add();

    That will return NaN (not 1), because even though the if (false) block doesn’t get executed and appears to do nothing, the var x floats up to the top of the function, which makes x undefined in the scope of the add function.

  4. Sorry for the late reply, but at least in IE8 (so most likely also in all previous versions).

  5. booleangate says:

    Indeed. Here's a more direct example of hoisting.

    if ( asdfghjkl in window ) {
    alert(“Ohai”);
    }

    var asdfghjkl;

Comments are closed now.