Better Understanding of Hoisting in JavaScript

      When it comes to Hoisting, the JavaScript language has some quirks which can lead to some very unexpected results. Take the following two snippets of code for example:

//function expression
var func1 = function(){
  console.log(20);
}

func1();

var func1 = function(){
  console.log(10);
};

//function declaration
function func1(){
  console.log(20);
}

func1();

function func1 (){
  console.log(10);
};

      What would you expect this log out? The answer to the first snipped is 20 while the answer to the second snipped is 10. Now let’s look at why.

      JavaScript function declarations are parsed at pre-execution stage, which means that they are hoisted to the top before the rest of the code is compiled. So let’s look at what the code will look like after this hoisting during compile time (note that this is not how the code was written, but how it is being run):

function func1(){
  console.log(20);
}

function func1 (){
  console.log(10);
};

func1();

This is why the code logs 10 instead of the expected 20.

      Now the same does not happen for function expressions. For function expressions the variables are hoisted to the beginning of the code, but they are only instantiated during runtime. Let’s look at how this would look like (again this is not how the code is written but what it would look like during runtime):

var func1;
var func1;

func1 = function(){
  console.log(20);
}

func1();

func1 = function(){
  console.log(10);
};

      As you can see both func1’s would be declared up top, but the first one would be replaced by the second which would then be instantiated. Let’s look at two more examples of function declaration and function expression:

func1();

var func1 = function(){
  console.log(10);
};

func1();

function func1 (){
  console.log(10);
}

What do both of these functions log out? The first one logs out an error and the second one logs out 10. So again let’s look at what both of them look like during compile time:

var func1;

func1();

func1 = function(){
  console.log(10);
};

function func1 (){
  console.log(10);
}

func1();

      In the first example func1 gets declared before the func1() call, but it’s not instantiated as a function until after func1() was called with a value set to undefined. In the second example the declared function gets hoisted to the top as a function and is available to be called at the time func1() is called.

      Now if you’ve been around JavaScript long enough none of this might have come as a surprise to you, but let’s look at one last example which I find very interesting:

var x = 5;
var x;
console.log(x);

      What would you expect this to log out? The answer is 5. JavaScript has the same Hoisting rules for variables that it has for declared functions. This shouldn’t come as a surprise since JavaScript treats functions as objects. If we once again look at how this gets compiled at runtime it becomes clear as to why this logs out 5 and not the expected undefined:

var x;
var x;
x=5;
console.log(x);

      During compile x is declared twice with the second declaration overriding the first, and only then is x instantiated with the value 5. Now lets look at one last example:

var x = 5;

var scopeFunction = function() {
  var x;
  console.log(x);
};

scopeFunction();

       What would you expect this to log out? The correct answer is undefined. If you are not sure why that is let's take a look how this snippet get compiled at run time.

var x;
var scopeFunction;
x = 5;
scopeFunction = function() {
  var x;
  console.log(x);
};
scopeFunction(); //is called creating a new scope
  var x;
  console.log(x); //console.log is called and looks for x in the current scope, x is found and logged out as undefined.

      The difference between this example and the previous ones is that the calling of a new function creates a new scope. When console.log searched for the value of x and finds it in the current scope and logs out that value.

      So as you can see once you understand the declaration and instantiation pattern of JavaScript it becomes far easier to understand why your code is behaving as it is.

Paulo Diniz