Sep 27, 2025

JavaScript Hoisting Explained: Temporal Dead Zone, var vs let vs const, and Best Practices

JavaScript hoisting is a fundamental concept that can sometimes confuse even experienced developers. Understanding it thoroughly helps avoid common pitfalls and write cleaner code. This post breaks down hoisting in variables, functions, and classes, explains the Temporal Dead Zone (TDZ), and highlights best practices to manage them effectively.

What is Hoisting?

Hoisting refers to JavaScript’s behaviour where declarations (not initializations) of variables, functions, and classes are moved—"hoisted"—to the top of their current scope before code execution. This means you can sometimes use variables or functions before you declare them in the code.

Hoisting in Variables: var vs let vs const

var declarations are hoisted and initialized with undefined. So accessing them before the declaration gives undefined, not an error.
let and const declarations are hoisted but not initialised. They stay in the Temporal Dead Zone (TDZ) from the start of the block until the line where they are declared. Accessing them before declaration causes a ReferenceError.

Temporal Dead Zone (TDZ) Explained

The TDZ is the time window between entering a scope and the actual initialisation of a let or const variable. During this time, the variable exists but can't be accessed.

Why reference errors occur:

JavaScript knows about x but forbids using it until its definition to avoid unpredictable behaviours.

Function Hoisting: Declarations vs Expressions

Function declarations are fully hoisted—including their bodies. You can call the function even before its declaration.
Function expressions (including arrow functions) assigned to var/let/const are only hoisted as variable declarations, but not initialised as functions. Calling them before initialisation throws an error.

Class Hoisting

Class declarations behave like let/const. The class is hoisted but not initialised — accessing before declaration triggers ReferenceError.

Execution Context: Hoisting + TDZ + Errors

When JavaScript runs code, it creates an Execution Context for each scope, including a variable environment. During the compile phase, declarations are hoisted, but initialisations happen during execution. 
Accessing uninitialized let, const, or classes causes errors due to TDZ. Understanding this helps debug unexpected ReferenceErrors and TypeErrors.
To understand execution context thoroughly, check out our post Execution Context Explained.

var vs let vs const in Practice

Feature
var
let
const
Hoisted
Yes
Yes
Yes
Initialized on hoisting
Yes (undefined)
No
No
TDZ present
No
Yes
Yes
Re-assignable
Yes
Yes
No
Block scoped
No (function)
Yes
Yes

Avoid Hoisting & TDZ Issues: Best Practices

  • Always declare variables at the top of scopes to avoid confusion.
  • Prefer const and let over var for clearer scoping and TDZ safety.
  • Avoid calling functions before declaration when using function expressions.
  • Use function declarations if you need hoisting, but understand scope rules.
  • Write code to minimise dependency on hoisting behaviour — it improves readability and reduces bugs.
  • Initialise variables at declaration whenever possible.

Summary Example

Understanding hoisting, Temporal Dead Zone(TDZ), and differences between declarations in JavaScript is key to mastering the language and writing robust, bug-free code.


EmoticonEmoticon