Skip to main content

Command Palette

Search for a command to run...

All about Hoisting in JavaScript

Updated
4 min read
All about Hoisting  in JavaScript

Hoisting is a very interesting mechanism in JavaScript that determines when the variable or function can be accessed. You must have noticed that we can access and use functions even before their declaration.

showMessage(); // "Hello everyone!"

function showMessage() {
  console.log("Hello everyone!");
}

It does not give an error because of hoisting. So let's jump in and understand what exactly it is and how it works in different situations with variables, functions, classes, and import modules. We'll also touch upon Temporal Dead Zone, which is undeniably linked with Hoisting.

What is hoisting?

JavaScript Hoisting refers to the process whereby the interpreter allocates memory for variable and function declarations before execution of the code. A more simple definition would be:

Hoisting is a JavaScript mechanism where all the variable and function definitions are automatically moved by the interpreter to the top of their scope before code execution.

So in the example above, the function declaration of showMessage is moved to the top of the scope. In this way when we call the function, we do not get an error.

Hoisting works differently in some cases. ES6 introduced let, const, and class that behaves differently with respect to hoisting.

Hoisting in Variables

Variables in JavaScript have 3 phases. First, they are declared, then they are initialized and finally used. Which typically ends up looking like this:

let charCode; // declaration
charCode = 97; // initialization
String.fromCharCode(charCode); // usage

// typically declaration and initialization are done together
let charCode = 97;

All variable declarations are hoisted to the top. Now var is fully hoisted, unlike let and const. Let's see how.

  • var

    Variables declared with var are hoisted to the top and initialized as undefined. Accessing variable before declaration gives us undefined but no error.

      console.log(a); // "undefined"
      var a = "Great!"
      console.log(a); // "Great"
    
  • let and const

    Variables declared with let and const work similarly when we talk about hoisting. Both are hoisted to the top but remain uninitialized. Accessing them before declaration gives us a ReferenceError. The zone between entering the scope and the declaration is the Temporal Dead Zone of that variable. Trying to access that variable in this zone, throws an error.

      // TDZ starts
      console.log(a); // ReferenceError: a is not defined
      const a = "constVariable"; // TDZ ends
    

Hoisting in Functions

Functions can be created using either function declaration or function expressions. Both behave differently with respect to hoisting.

  • Function Declarations

    They are fully hoisted to the top of their scope before code execution. So we can freely call functions even before the function declaration.

      sayHello("Alex"); // "Hello Alex!"
      function sayHello(name) {
          console.log(`Hello ${name}!`);
      }
    
  • Function Expressions

    The hoisting of functions created using expressions depends on the variable in which the function is stored in. They are hoisted, as all variable declarations are hoisted, but gives an error if we try to call the function before the declaration.

      fnExp(); // Output: "ReferenceError: fnExp is not defined"
    
      const fnExp = function() {
        console.log("Hello!");
      };
    

    In the case of let and const, the variable gets hoisted to the top and is uninitialized. Trying to call the function before declaration will give a ReferenceError.

      fnExp(); // "TypeError: fnExp is not a function"
    
      var fnExp = function() {
        console.log("Hello!");
      };
    

    In the case of var, the variable gets hoisted to the top and is initialized as undefined. Calling the function before declaration gives a TypeError as it's not a function at the moment.

Hoisting in Class

Classes can also be classified into class declaration or class expression. Both are hoisted but give an error if we try to access them before the declaration.

  • Class declaration

    Class declarations are also hoisted but are uninitialized. Accessing them before declaration gives a ReferenceError. Affected by Temporal Dead Zone.

      const person1 = new Person("Alex"); // ReferenceError: Person is not defined
    
      class Person {
        constructor(name) {
          this.name = name;
        }
      }
    
  • Class expression

    Class expressions are hoisted but accessing them before declaration gives an error, depending on the variable in which it is stored. Similar to function expressions.

      const person1 = new Person("Alex"); // TypeError: Person is not a constructor
    
      var Person = class {
        constructor(name) {
          this.name = name;
        }
      }
    

    Person is declared using var, so it gets hoisted to the top and initialized as undefined. Here JavaScript tries to invoke undefined as a constructor when it is not. So it returns a TypeError.

That's it! There are also things like import modules that are hoisted and can be accessed before declaration. But should always be declared on the top as a good practice.

Hope you took something away from this article. If you found this helpful - like, comment, and share.

Thank you for reading.