What is Hoisting in JavaScript?

When your JavaScript is being compiled, variables and function definitions are made available to the JavaScript engine. When the engine executes your code, the declared vars and functions from the compilation phase are made available before their value assignments, irrespective of the order in which they were written.

This can be envisaged as “hoisting” the declarations to the top of the current scope. The variable value assignments on the other hand are in place where they were authored, below the declarations.

This is why you can call functions that are declared underneath the invoking code.


  someFunction();
  
  function someFunction() {
    console.log(“Hello”); // Hello
  }

The JavaScript engine sees this as:


  function someFunction() {
    console.log(“Hello”); // Hello
  }
 
  someFunction();

The function declaration is available to the JS engine at the top of the scope. This is the same with vars, but only the declaration, not the assignment of a value to the var.


  console.log(x); // undefined
  var x = 1;

Note the value of x is the value undefined, and not a ReferenceError. This is because the JavaScript engine sees it as:


  var x; // declaration hoisted only, not the assignment
  console.log(x); // undefined
  x = 1;

This can have unexpected results if you declare variables and functions with the same name, or declare them further down in the code (mistakenly or otherwise) after assigning them values.

While true for vars and functions, let and const declarations are not hoisted.


  console.log(x); // ReferenceError: Cannot access 'x' before initialization
  let x = 1;

Note the ReferenceError in this example; the let declaration is not “hoisted” or declared above the console.log(x), as it was with var.

Note that the vars and functions are hoisted relative to the current scope, so the usual lexical scope rules apply for functions and variables declared in functions, they are not hoisted to the top of the global scope.


  var a = 1;
  
  someFunction();
  
  function someFunction() {
  
    anotherFunction();
    
    function anotherFunction() {
      console.log(a); // 1
    }
  }
  
  anotherFunction();  // ReferenceError: anotherFunction is not defined
                      // anotherFunction remains within the scope of someFunction

Seen by the JS engine as:


  var a;
  a = 1;
  
  function someFunction() {
  
    function anotherFunction() {
      console.log(a); // 1
    }
    
    anotherFunction();
  }
  
  someFunction();
  
  anotherFunction();  // ReferenceError: anotherFunction is not defined
                      // anotherFunction remains within the scope of someFunction

It’s therefore common practice to declare vars before assigning them values (or at the same time as assigning values), placing them at the top of the current scope to avoid confusion. Bear in mind that lets and consts will not be available for reference before declaration (and will result in a ReferenceError), as they are with vars.

If you have any questions or comments or want to connect, you can follow me on Twitter, or sign up to the newsletter in the footer for front-end articles to your inbox 👇


Back home