The Ultimate Guide to JavaScript Hoisting and the Temporal Dead Zone (2026)

If you have spent any time writing JavaScript, you have likely heard the term hoisting. The classic explanation is that JavaScript “moves” all your variables and functions to the top of your file before running the code.

While that is a helpful mental model for beginners, it is technically false. Your code doesn’t physically move anywhere.

To truly master modern JavaScript—and avoid frustrating ReferenceError bugs—you need to understand what the JavaScript engine is actually doing during the compilation phase, how different keywords (var, let, const) react, and how the Temporal Dead Zone (TDZ) protects your code.

Let’s break down exactly how hoisting works under the hood.

The Myth vs. The Reality

When you run a JavaScript file, the engine doesn’t just read it top-to-bottom and execute it immediately. It actually does it in two distinct phases:

  1. The Memory Creation Phase (Compilation): The engine parses your code, looks for variable and function declarations, and sets up memory space for them before executing a single line of logic.
  2. The Execution Phase: The engine runs your code line by line, assigning values and executing functions.
image

{/* Reason: Visualizes the two-phase execution context, which is critical to understanding that code isn’t physically “moved”, but allocated in memory first. */}

Hoisting is simply the result of this two-step process. Because declarations are put into memory during phase one, they are technically accessible during phase two, even if the actual line of code hasn’t been reached yet.

However, how they are accessible depends entirely on how you declare them.

Variable Hoisting: The Legacy of var

Before ES6 (ES2015), var was the only way to declare variables. When the JavaScript engine hoists a var declaration, it does two things:

  1. It allocates memory for the variable.
  2. It automatically initializes it with a value of undefined.
image

Notice that it doesn’t throw an error on line 1. The engine knows username exists, but because the assignment (= "BitsBytesGo") happens during the execution phase, it defaults to undefined. This behavior has caused countless bugs in older JavaScript codebases.

Modern Variables: let, const, and the TDZ

Modern JavaScript introduced let and const to solve the unpredictable nature of var.

Are let and const hoisted? Yes. But they behave differently. When the engine hoists let and const, it allocates memory for them, but it does not initialize them with undefined. They remain completely uninitialized.

If you try to access them before the engine reaches their actual line of code, JavaScript throws a ReferenceError.

image

This period of time—between entering the scope (like the top of a file or the start of a block) and the actual declaration line—is called the Temporal Dead Zone (TDZ).

image

{/* Reason: Visually maps the exact lines of code where a variable exists in the TDZ, clarifying a highly abstract concept for visual learners. */}

The TDZ is a safety feature. It forces you to declare your variables before you use them, leading to cleaner, more predictable code.

Function Hoisting

Functions have their own specific hoisting rules depending on how they are written.

1. Function Declarations (Fully Hoisted)

Standard function declarations are completely hoisted. The engine stores both the function’s name and its entire body in memory during the creation phase. This means you can call a function at the top of your script while defining it at the bottom.

image

This is actually a highly useful feature. It allows developers to put their main executable code at the top of a file and hide the helper functions at the bottom, improving readability.

2. Function Expressions & Arrow Functions (Variable Rules Apply)

If you assign a function to a variable, it follows the hoisting rules of that variable keyword.

image

Class Hoisting

Classes in JavaScript (introduced in ES6) are hoisted in the exact same way as let and const. The class declaration is hoisted to the top of its scope, but it remains in the Temporal Dead Zone until the execution reaches it. You cannot instantiate a class before it is defined.

image

Order of Precedence

What happens if a variable and a function share the same name? The JavaScript engine has a strict priority order during the memory creation phase:

  1. Functions are hoisted first.
  2. Variables are hoisted second.

If a variable declaration (without assignment) shares a name with a function, the function wins. However, if the variable is assigned a value, that assignment will overwrite the function during the execution phase.

Best Practices for 2026

Hoisting is a fascinating look into how the V8 engine works, but as a modern developer, your goal should be to write code where hoisting quirks never affect your logic.

  1. Stop using var entirely. Stick to const by default, and use let only when you know the value will be reassigned (like in a loop counter).
  2. Declare variables at the top of their scope. Whether it’s the top of a file or the top of a function block, keep your declarations together.
  3. Use ES Modules (import/export). Modules automatically run in Strict Mode ("use strict"), which catches silent hoisting errors and forces better declaration habits.

Understanding hoisting doesn’t just help you pass technical interviews—it fundamentally changes how you debug your code. The next time you see Cannot access before initialization, you’ll know exactly what the engine is complaining about.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top