What is hoisting in JavaScript?

JavaScript, Type, Variable · Jun 12, 2021

Before your JavaScript code is executed, it is first parsed and compiled. During the compile phase, variable and function declarations are put into memory, which is called hoisting.

Note that only declarations are hoisted, not initializations, meaning that if a variable is declared and initialized after using it, its value will not be initialized. This is an oversimplification of the situation, so let's take a look at the different cases:

function

When using function declarations, the function can be called before it's defined and it will work as expected. For example:

hello(); // logs 'Hello world!'

function hello() {
  console.log('Hello world!');
}

hello(); // logs 'Hello world!'

In the example above the function declaration is hoisted to the top of its scope and, due to the nature of function declarations, it's available before it's declared. However, this is the only case that behaves this way.

var

var declarations on the other hand behave differently, returning undefined when accessed before initialization. For example:

console.log(x); // logs 'undefined'
f(); // throws 'Uncaught TypeError: f is not a function'

var x = 1;
var f = () => 'Hi!';

console.log(x); // logs '1'
f(); // returns 'Hi!'

As you can see in this example, the var declarations are hoisted to the top of their scope, but their values are not initialized until the code that initializes them executes, thus being undefined up until that point.

const and let

Finally, const and let declarations are hoisted, but they are not initialized to undefined. Instead, they will give you an error, which is also how class declarations behave. For example:

console.log(y); // throws 'Uncaught ReferenceError: Cannot access "y" before initialization'
g();  // throws 'Uncaught ReferenceError: Cannot access "g" before initialization'

let y = 2;
const g = () => 'Hey!';

console.log(y); // logs '2'
f(); // returns 'Hey!'

Generally, const and let provide more of a headache-free experience for a variety of reasons and this is no exception. Where accessing variables declared with var before initialization fails silently, doing the same for const or let results in a clear, easy to debug error.

Best practices

  • Always define variables, functions, objects and classes before using them. ESLint can probably help you with that.
  • If your environment/team allows it, prefer const and letover var to minimize headaches.
  • If possible, use only arrow functions or function declarations. Consistency can help reduce confusion.

Written by Angelos Chalaris

I'm Angelos Chalaris, a JavaScript software engineer, based in Athens, Greece. The best snippets from my coding adventures are published here to help others learn to code.

If you want to keep in touch, follow me on GitHub or Twitter.

More like this

  • What are truthy and falsy values in JavaScript?

    JavaScript uses type coercion in Boolean contexts, resulting in truthy or falsy values. Get a hang of how it all works in this quick guide.

    JavaScript, Type · Sep 12, 2021

  • Collection is empty

    Checks if the a value is an empty object/collection, has no enumerable properties or is any type that is not considered a collection.

    JavaScript, Type · Oct 20, 2020

  • Understanding JavaScript variables and scopes

    JavaScript developers often get confused by JavaScript's variables and scope. Here's a quick guide to understanding and remembering everything related to these concepts.

    JavaScript, Type · Jun 12, 2021