Order of hoisting in JavaScript

function g () {
    var x;
    function y () {};
    var z;
}

I would like to know exactly what order the above code becomes when hoisted.

Theory 1: Order between vars and functions remains as-is:

function g () {
    var x;
    function y () {};
    var z;
}

Theory 2: vars come before functions:

function g () {
    var x;
    var z;
    function y () {};
}

Theory 3: functions come before vars:

function g () {
    function y () {};
    var x;
    var z;
}

Which theory is correct?


Solution 1:

Functions are hoisted first, then variable declarations, per ECMAScript 5, section 10.5 which specifies how hoisting happens:

We first have step 5 handling function declarations:

For each FunctionDeclaration f in code, in source text order do...

Then step 8 handles var declarations:

For each VariableDeclaration and VariableDeclarationNoIn d in code, in source text order do...

So, functions are given higher priority than var statements, since the later var statements cannot overwrite a previously-handled function declaration. (Substep 8c enforces the condition "If varAlreadyDeclared is false, then [continue...]" so extant variable bindings are not overwritten.)

You can also see this experimentally:

function f(){}
var f;
console.log(f);

var g;
function g(){}
console.log(g);

Both log calls show the function, not an undefined value.

Solution 2:

Although the order was fixed by the specification, as the accepted answer points out, that order really is not that important.

  • var declarations are hoisted, but not their initialisation (if there is one). A var declaration is without effect if the name is already taken by a function or other var declaration.
  • function definitions are hoisted -- not only declaring the name, but also their value, i.e. the function.

So the following two pieces of code:

(function () {
    console.log(typeof a);
    var a = 1;
    function a() { }
})();

and:

(function () {
    console.log(typeof a);
    function a() { }
    var a = 1;
})();

... translate to:

(function () {
    function a() { }
    var a;
    console.log(typeof a);
    a = 1;
})();

and respectively:

(function () {
    var a;
    function a() { }
    console.log(typeof a);
    a = 1;
})();

The latter two are the same thing really. If the engine processes the hoisted var declaration first, then a is first undefined but then immediately overwritten as function. If on the other hand the function definition is processed first, then the var declaration has no effect. In both scenarios the outcome is the same.