JavaScript Variable Scope

JavaScript scopes variables in a unique way that often confuses developers coming from other languages. First, as discussed in the Context Binding Functions article, the this keyword is dynamic, and second, as we᾿ll discuss today, variable scopes change depending on how you declare them.

How do it…

The most basic way to declare a variable is:

var foo1 = 'bar';

The variable foo1 will be added to the current execution context (window in this case). Here it will be added to a function’s execution context:

function baz() {
    var foo2 = 'bar';
}

In this second case foo2 will only be available inside baz. However, you don’t need to include var when defining a variable:

foo1 = 'bar';

function baz() {
    foo2 = 'bar';
}

This code adds both foo1 and foo2 to the window execution context, even though foo2 is inside a function. It doesn’t matter how deep the function chain is, if there is no var, then the variable will bind to window:

function baz() {
    (function() {
        (function() {
            (function() {
                foo2 = 'bar';
            }());
        }());
    }());
}

Additionally, the window context is available as a first class object, and you can manually bind variables to it:

window.foo1 = 'bar';

function baz() {
    window.foo2 = 'bar';
}

Next, you need to understand that variables defined in the execution context outside of a function are also available in the execution context inside a function:

var foo = 'bar';

function baz() {
    alert(foo); // will alert 'bar'
}

The compiler first looks for the variable foo in the current execution context, then it moves up the scope chain to the next context, and so on until window. An error will be thrown if foo isn’t defined in any execution context in the scope chain. Again, this is true, no matter the how deep the function chain is:

function baz() {
    (function() {
        (function() {
            (function() {
                alert(foo); // will alert 'bar'
            }());
        }());
    }());
}

Function arguments are scoped to the execution context of the function and behave as variables declared with var:

var foo = 'bar1';
function baz(foo) {
    alert(foo); // will be 'bar2'
}
baz('bar2');

How it works…

To summarize, variables can be declared with or without var, but excluding the var will cause the compiler to search the scope chain for the variable, adding it to window if the variable doesn’t exist yet in the scope chain. If there are multiple variables of the same name in the scope chain, the first one found will be used, and all others will be masked. You may, however, access masked variable names on the window object by referencing them as you would an object property (window.NAME_OF_VARIABLE). Lastly, function arguments are defined inside the execution context of the function and will mask any variables in the scope chain of the same name.