DEV Community

Cover image for JavaScript Hoisting: What It Is And Why It Was Implemented
James Won
James Won

Posted on

JavaScript Hoisting: What It Is And Why It Was Implemented

Hoisting is a key concept in JavaScript that can cause unexpected behavior in your code if you're not aware of how it works.

JavaScript Hoisting refers to the process whereby the interpreter appears to move the declaration of functions, variables or classes to the top of their scope, prior to execution of the code. - MDN

Hoisting Variables

  1. If you declare a variable after its first usage, this variable declaration is "hoisted" to the top of its scope.
  2. If you assign a value to the variable, then the order it is assigned is unchanged and is unaffected by the hoisting.

See the following simple example.

function myFunction() {
  console.log(myHoistedVariable); // undefined for ES5 and below
  var myHoistedVariable= 1;
  console.log(myHoistedVariable); // 1
}
Enter fullscreen mode Exit fullscreen mode
  1. Since the declaration of myHoistedVariable is hoisted, the first console.log will attempt to print out the value (Note. the actual result will differ depending on if you use var, let or const)

  2. The console.log will print undefined as the assignment of the value 1 isn't moved along with the hoisting (Note. this is for ES5 only using var).

The above example, basically is the same as the following code:

function myFunction() {
  var myHoistedVariable
  console.log(myHoistedVariable); // undefined for ES5 and below or ReferenceError for ES6 `let` or `const`
  myHoistedVariable = 1;
  console.log(myHoistedVariable); // 1
}
Enter fullscreen mode Exit fullscreen mode

Note. ES5 v ES6
While hoisting technically still occurs with ES6, in practical effects you will be prevented from using it.

  • ES5: If you are using var a hoisted value will return undefined . This behaviour is called Type 2 hoisting behaviour by MDN.
  • ES6: For let and const declarations are also hoisted to the top of their scope, but they are not initialized with a value of undefined.

Practically, this means you cannot use a let or const variable before it's declared, or you will get a ReferenceError. This is called Type 3 hoisting behaviour by MDN.

If you declare a JavaScript file with 'use strict'; this will mean that hoisting using var will throw a Type 3 ReferenceError. (See this article from Digital Ocean for more info)

Hoisting Functions

Hoisting for functions get a bit more interesting:

  • Function declarations are hoisted to the top of their scope. This means that you can call functions before they are declared.
myHoistedFunction();

function myHoistedFunction() {
    console.log("Hi I'm hoisted!");
}
Enter fullscreen mode Exit fullscreen mode
  • Function expressions are not hoisted. This means that if you declare a function expression using const or let you cannot call the function before this declaration. This is also the case for arrow functions as they are also function expressions.

Why hoist at all??? 🤔

If this all seems pretty random and unnecessary, it did to me too - especially hoisting variables.

Why wouldn't you just enforce everyone to declare variables, functions and classes at the top of their scope? Even though this is largely corrected in ES6 and the move towards function expressions as the conventional norm (another hot topic for another day).

Historical reasons

Digging into this a bit further I found this tweet from the archives:

@aravind030792 var hoisting was thus unintended consequence of function hoisting, no block scope, JS as a 1995 rush job. ES6 'let' may help.

— BrendanEich (@BrendanEich) October 15, 2014

This article on Quora explains this further. **TL;DR **Brendan Eich when implementing JavaScript (AKA LiveScript) in 10 days wanted to avoid the painful top to bottom enforcement of function declarations in ML languages like Lisp.

Brendan also followed up with a following tweet clarifying that var hoisting was unintended:

@aravind030792 var hoisting was thus unintended consequence of function hoisting, no block scope, JS as a 1995 rush job. ES6 'let' may help.

— BrendanEich (@BrendanEich) October 15, 2014

From this context - the feature does make sense.

Interpreter performance reasons

When the JavaScript engine compiles code, it first goes through a process called parsing, where it breaks down code into smaller, more manageable pieces.

By moving function declarations to the top of their scope before execution, the interpreter can avoid the need to search for the declaration of the function each time it is called. Instead, it can simply execute the function directly from memory, which can be faster and more efficient.

To summarise, it appears there are two key benefits of Hoisting:

  1. Allow you to use function declarations before they are defined. This allows you to organise where you put your function code regardless of where they are called as long as they are within the same scope.

  2. Improve the performance of the interpreter. Because variable declarations are moved to the top of their scope during compilation this may reduce the time the JavaScript engine needs to parse the code.

Some great resources on Hoisting/reading material related to the topic:

Top comments (0)