19
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?

ElChiniNet
  • 2,778
  • 2
  • 19
  • 27
mareoraft
  • 3,474
  • 4
  • 26
  • 62

2 Answers2

29

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.

Paul
  • 139,544
  • 27
  • 275
  • 264
apsillers
  • 112,806
  • 17
  • 235
  • 239
  • 6
    To be perfectly clear, he is saying that `function`s come before `var`s, which is Theory 3 in the OP. – mareoraft Jan 31 '15 at 01:41
  • FWIW, this has changed some time in the latest versions. I believe the binding for both are now created at the same time (e.g. step 27) and at the end the actual function value is assigned (step 36). But I could be misreading this. https://www.ecma-international.org/ecma-262/9.0/index.html#sec-functiondeclarationinstantiation – Felix Kling May 03 '19 at 18:01
  • This is interesting for me why Ecma Scpesfication acept rule like that? What is reason give functions higher priority than var statements? – Murad Sofiyev Aug 17 '19 at 20:41
10

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.

trincot
  • 317,000
  • 35
  • 244
  • 286