Hoisting

This is, perhaps, the most important conclusion of everything we’ve learned above — and maybe the most interesting too.

Let's look at two scenarios:

Scenario 1:

a = 2;



var a;



console.log( a ); // 2 Scenario 2:

console.log( a ); // undefined



var a = 2;

Now the reason why the outputs might seem confusing is because of hoisting.

The JS engine works in two steps: The first is the compilation phase, and the next is the execution phase. The work of these two steps is different.

In the compilation phase, all variables and function declarations are processed.

After the compilation phase, in the execution phase, all the logic and assignments take place.

When you see var a = 2; , you probably think of that as one statement. But JavaScript actually thinks of it as two statements: var a; and a = 2; . The first statement, the declaration, is processed during the compilation phase. The second statement, the assignment, is left in place for the execution phase.

Note: In the above example, the in place part is very important. It’s also important to note that hoisting is per scope.

Our first snippet will then be:

var a; a = 2;



console.log( a ); // 2

And our second snippet:

var a; console.log( a ); //undefined



a = 2;

Functions first

A subtle yet important detail: Functions are hoisted first — and then variables.

Consider:

foo(); // 1 var foo; function foo() {

console.log( 1 );

} foo = function() {

console.log( 2 );

};

1 is printed instead of 2 . This snippet is interpreted by the engine as:

function foo() {

console.log( 1 );

} foo(); // 1 foo = function() {

console.log( 2 );

};

While multiple/duplicate var declarations are effectively ignored, subsequent function declarations do override previous ones.

Consider the next two snippets:

Snippet 1:

foo(); // 3 since the second function decalaration overrides the first one.



function foo() {

console.log( 1 );

}



var foo = function() {

console.log( 2 );

};



function foo() {

console.log( 3 );

}

Snippet 2:

foo(); // "b"



var a = true;

if (a) {

function foo() { console.log( "a" ); }

}

else {

function foo() { console.log( "b" ); }

}

Function declarations that appear inside of normal blocks typically hoist to the enclosing scope, rather than being conditional, as the above code implies.