JavaScript - - By Colin Ihrig

Back to Basics: JavaScript Hoisting

Variable declarations are one of the most basic aspects of any programming language. However, JavaScript has a little quirk, known as hoisting, which can turn an innocent looking declaration into a subtle bug. This article explains what hoisting is, and how you can avoid being burned by it.

JavaScript is an extremely flexible language, and will happily allow you to declare a variable almost anywhere. For example, the following immediately-invoked function expression (IIFE) declares three variables and then displays them using an alert dialog box. As a side note, you should never use alert boxes, but we’re trying to prove a point here.

(function() {
  var foo = 1;
  var bar = 2;
  var baz = 3;

  alert(foo + " " + bar + " " + baz);
})();

This looks like sane JavaScript code. As expected, it displays the string "1 2 3". Now, assume that the alert is moved, as shown below.

(function() {
  var foo = 1;
  alert(foo + " " + bar + " " + baz);
  var bar = 2;
  var baz = 3;
})();

If someone actually wrote this code, it was probably by mistake. Clearly, the alert takes place before bar and baz are declared. However, this is perfectly valid JavaScript, which does not generate an exception. Instead, the alert displays "1 undefined undefined".

Based on our previous experiment, it seems that you can reference variables that don’t exist yet. Now, let’s take the same IIFE, but remove the baz declaration altogether, as shown below. Suddenly, we have a ReferenceError because baz is not defined.

(function() {
  var foo = 1;
  alert(foo + " " + bar + " " + baz);
  var bar = 2;
})();

This is truly interesting behavior. To understand what’s going on here, you have to understand hoisting. Hoisting is the JavaScript interpreter’s action of moving all variable and function declarations to the top of the current scope. However, only the actual declarations are hoisted. Any assignments are left where they are. Therefore, our second example IIFE actually translates to the following code.

(function() {
  var foo;
  var bar;
  var baz;

  foo = 1;
  alert(foo + " " + bar + " " + baz);
  bar = 2;
  baz = 3;
})();

Now it makes sense why the second example didn’t generate an exception. After hoisting, bar and baz are actually declared before the alert statement, albeit with undefined values. In the third example, baz was removed completely. Therefore, there was nothing to hoist, and the alert statement resulted in an exception.

Function Hoisting

As previously mentioned, function declarations are also hoisted. However, functions that are assigned to variables are not hoisted. For example, the following code will work as expected due to function declaration hoisting.

foo();

function foo() {
  alert("Hello!");
}

However, the following example will fail spectacularly. The variable declaration for foo is hoisted before the function call. However, since the assignment to foo is not hoisted, an exception is thrown for trying to call a non-function variable.

foo();

var foo = function() {
  alert("Hello!");
};

Conclusion

Hoisting is an easy to understand, but often overlooked nuance of the JavaScript language. Without a proper understanding of hoisting, your programs are susceptible to subtle bugs. To help avoid these bugs, many developers (and linting tools) advocate for a single variable declaration statement at the very beginning of every scope. Since this is how the JavaScript interpreter essentially sees your code, there is validity to this rule – even if I am personally guilty of breaking it.

Sponsors
Login or Create Account to Comment
Login Create Account