JavaScript Hoisting

 Reading time ~5 minutes

Heads up: this article is over a year old. Some information might be out of date, as I don't always update older articles.

Introduction

In this post I am going to talk about JavaScript. Recently I rediscovered this programming language, after a long time distance caused mainly by its quirks. However while working on my thesis I started to enjoy this language and I realized how much powerful it can be, if used in the correct way.

“Do you want to work with the Web? Better learn JavaScript” said once a teacher of mine.

Therefore with a series of posts I’m going to analyze those little irregularities that make JavaScript less intuitive, providing endless arguments to the people that hates it. Mastering these inconsistencies distinguish the experienced programmer with the newbie.

Notice: the article assumes some basic experience in JavaScript from the reader.

Variable Hoisting

Let’s start talking about “hoisting”. There are a couple of premises before diggin in the code. I’m assuming that you know the difference between declaration and initialization of a variable. Assuming myvalue as the name of our variable, we can write

Declaration

var myvalue;

Initialization

var myValue = 1;

In the second case the variable is initialized with a value. You can use the typeof operator to know the type of the variable. In the first case is undefined while in the second it is a number.

alert(typeof myvalue);

Another factor that we have to take into account is the scope. For those of you that come from C family languages (C, C++, Java, Pascal…) the following code it’s easy to interpret:

#include <stdio.h>
int main() {
  int x = 1;
  printf("%d, ", x); // output: 1
  if(1) {
    int x = 2;
    printf("%d ", x); // output: 2
  }
  printf("%d\n", x); // output: 1
}

The output of the program is 1, 2, 1. That’s because C-like languages have block-level scope. Therefore when the program exectues the if block, a new variable x can be initialized without overwriting the same x outside the block. In JavaScript the code behaves differently. Let’s try to translate the previous code in JS:

var x = 1;
alert(x); // output: 1
if(true) {
  var x = 2;
  alert(x); // output: 2
}
alert(x); // output: 2

Surprisingly the output will be 1, 2, 2. Why? Because JavaScript, unlike C-family languages, has funcion-level scope, blocks like if or while don’t create a new scope.

Now consider the following code:

var myValue = 1;
alert(myValue); // output: 1

The alert will show 1 as output. We can try to slightly edit this code introducing a self-invoked anonymous function (which executes exactly where it is declared)

var myValue = 1;
(function() {
  alert(myValue); // output: 1
}());

The output is still 1. Good! Now let’s introduce a new complexity:

var myValue = 1;
(function() {
  alert(myValue); // output: ?
  var myValue = 2;
}());

What is the output in this case? Go ahead and try this code in Firebug/Developer/jsFiddle or your favourite tool for live coding, you will see that the alert value is undefined. Why? Our intuition tells us that the value should be 1 because the second initialization of myvalue is under the alert instruction.

It’s here that the hoisting concept comes into play. Variable and function declarations are always “hoisted” up, invisibly by the JavaScript interpreter, at the top their containing scope. Therefore the previous code is perfectly similar to the following:

var myValue = 1;
(function() {
  var myValue;
  alert(myValue); // output: undefined
  myValue = 2;
}());

Now you’re starting to understand how it works, is’n it?

Function Hoisting

In this section we are going to examine the “hoisting” concept in the case of functions.

function myfunc() {
  foo();
  function foo() {
    alert("it works");
  }
}
myfunc();

The hoisting concept applies here as well. The JS interpreter moves up the declaration of foo before its calling. The output clearly is “it works”, as one might expect. However we know that in JS there is a different way to declare functions, assigning them to variables (function expressions):

function myfunc() {
  foo();
  var foo = function() {
    alert("it doesn't work");
  }
}
myfunc();

In this case we will get an error (Uncaught TypeError: undefined is not a function) because only the name of the function (foo) is hoisted up, while the body of the function is assigned to the variable during the execution, therefore only after the foo call. The previous code is perfectly similar to the following:

function myfunc() {
  var foo;
  foo();
  foo = function() {
    alert("it doesn't work");
  }
}
myfunc();

Our analysis can end here, although there are still many particular cases in which the game becomes harder. The most important lesson that we could take from this post is to declare our variables with a single var instruction limited to the scope, placed exactly in the top of our functions, in order to avoid the hoisting confusion.

function myfunc() {
  var x,y,z;
  // code
  x = 1;
  // more code
  y = 2;
  // more code
  z = 3;
  // more code
  return;
}

If the argument is still relevant to you and you like challenge yourself, there’s a little quiz available to the following address http://www.nczonline.net/blog/2010/01/26/answering-baranovskiys-javascript-quiz/.

Reccommended Book: Douglas Crockford - JavaScript: the good parts

comments powered by Disqus