JavaScript Hoisting: Variables, Functions, and More

Hero image for JavaScript Hoisting: Variables, Functions, and More. Image by Ries Bosch.
Hero image for 'JavaScript Hoisting: Variables, Functions, and More.' Image by Ries Bosch.

In JavaScript, understanding hoisting is fundamental to writing reliable and predictable code. This unique feature (some might argue it's a "quirk") affects how variables and functions are initialised and accessed during the execution of a script.

In this article, I intend to explore what hoisting is, how it works with variables and functions, and best practices for managing hoisting within modern JavaScript.


What is Hoisting?

Hoisting is JavaScript's default behaviour of moving variable and function declarations to the top of their containing scope during the compilation phase. During the first step, the JavaScript interpreter processes variable and function declaration, but does not execute any of the code until the second step. This means that you can use variables and functions in your code before declaring them, albeit with some caveats.

For example:

console.log(myVar);  // undefinedvar myVar = 'Hello';

In this example, JavaScript "hoists" the var declaration to the top of its scope, but its value assignment remains in place. As a result, the variable is accessible before its declaration, but it returns undefined.


Hoisting in Variables

var and Hoisting

Variables declared with var are hoisted to the top of their scope. However, only the declaration is hoisted, not the initialisation.

Take this code for example:

console.log(greeting);  // undefinedvar greeting = 'Hi!';

The JavaScript engine will interpret this code like this:

var greeting;console.log(greeting);  // undefinedgreeting = 'Hi!';

let and const

Variables declared with let and const are also hoisted, but they remain in a "temporal dead zone" (TDZ) until their declaration is encountered.

console.log(message);  // ReferenceError: Cannot access 'message' before initialisationlet message = 'Hello!';

The temporal dead zone ensures that you cannot access the variable before it is declared, which eliminates one of the common pitfalls associated with var, and means that we get a ReferenceError instead of undefined.


Hoisting in Functions

Function Declarations

Function declarations are fully hoisted, meaning you can call the function before it is defined in your code.

For example:

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

Although perhaps not best practice, this is possible because the entire function is hoisted to the top of its scope.

Function Expressions

Function expressions, including arrow functions, are not fully hoisted. Only the variable declaration is hoisted, not the function itself:

sayHello();  // TypeError: sayHello is not a functionvar sayHello = function () {  console.log('Hello, world!');};

The JavaScript engine interprets this as:

var sayHello;sayHello();  // TypeErrorsayHello = function () {  console.log('Hello, world!');};

Best Practices for Managing Hoisting

1. Use let and const Instead of var

Avoid var in modern JavaScript (there really is very little reason you would ever use var) to prevent unexpected behaviour due to hoisting. Stick to let and const for blockscoped variables.

const name = 'Sophie';let age = 30;

2. Declare Variables and Functions at the Top of Their Scope

Explicitly declaring variables and functions at the beginning of their scope reduces the potential for hoistingrelated confusion. It also makes it much easier to read, especially for the developer who comes to your code after you!

function processData() {  let data;  // Logic goes here}

3. Initialise Variables Immediately

Wherever possible, declare and initialise variables in a single step to avoid accessing uninitialised values.

let user = 'John';

Wrapping up

Hoisting is an essential aspect of JavaScript's behaviour that can sometimes lead to unexpected results, especially in relatively new or inexperienced developers. Understanding how hoisting works with variables and functions is key to writing predictable and maintainable code. By using modern features like let and const, and following best practices, we can minimise the risks associated with hoisting.

Key Takeaways

  • What is hoisting?
    JavaScript moves declarations (not initialisations) to the top of their scope during compilation.
  • Variables:
    var is hoisted, but its initialisation is not; let and const remain in a temporal dead zone until declared.
  • Functions:
    Function declarations are fully hoisted, but function expressions are not.
  • Best practices:
    Use let and const, declare variables and functions at the start of their scope, and initialise variables immediately.

Hoisting is a quirk of JavaScript, but with a clear understanding and modern practices, we can avoid its pitfalls and write cleaner, more reliable code.


Categories:

  1. Development
  2. Front‑End Development
  3. Guides
  4. JavaScript