Technical Publication2025-02-07

JavaScript Hoisting: Mechanics, Pitfalls, and Best Practices

Hoisting Mechanism

What is Hoisting?

Hoisting is a fundamental JavaScript behavior that defines how variable and function declarations are registered during the creation phase of the execution context before code execution begins.

Hoisting is JavaScript's mechanism of allocating memory for variable and function declarations prior to executing line-by-line code.

Core Facts:

  • Declarations are hoisted, but initializations are not.
  • Function declarations are hoisted completely, allowing them to be invoked before their textual definition.
  • let and const declarations are hoisted into the Temporal Dead Zone (TDZ) and remain uninitialized until execution reaches their definition.

Variable Hoisting

var Declarations

Variables declared with var are hoisted to the top of their enclosing function or global scope and initialized with undefined.

Example:

JAVASCRIPT
1console.log(a); // Output: undefined 2var a = 10; 3console.log(a); // Output: 10

Under the hood:

JAVASCRIPT
1var a; // Declaration is hoisted and initialized to undefined 2a = 10; // Assignment happens during the execution phase

let and const Declarations

Unlike var, variables declared with let and const are hoisted without initialization. Accessing them before their declaration line results in a ReferenceError.

Example:

JAVASCRIPT
1console.log(b); // ReferenceError: Cannot access 'b' before initialization 2let b = 20;

This behavior is caused by the Temporal Dead Zone (TDZ), which protects variables from premature access.


Function Hoisting

Function Declarations

Function declarations are hoisted with their complete function bodies, enabling calls before their definition in the source file.

Example:

JAVASCRIPT
1sayHello(); // Output: Hello, world! 2 3function sayHello() { 4 console.log("Hello, world!"); 5}

Function Expressions and Arrow Functions

Function expressions and arrow functions assigned to variables follow variable hoisting rules rather than function hoisting rules.

Example:

JAVASCRIPT
1sayHi(); // TypeError: sayHi is not a function 2 3var sayHi = function() { 4 console.log("Hi!"); 5};

JavaScript hoists sayHi as a variable with value undefined. Attempting to invoke undefined() throws a TypeError.


Summary Comparison

Featurevarlet and constFunction DeclarationFunction Expression
Hoisted?YesYes (in TDZ)YesFollows variable type
Usable before declaration?Yes (undefined)No (ReferenceError)YesNo (TypeError / ReferenceError)

Best Practices

  • Prefer const and let over var to enforce block scoping and prevent accidental hoisting side effects.
  • Declare variables at the top of their respective scopes for clarity and readability.
  • Maintain consistent function declaration styles and understand the scope constraints of the Temporal Dead Zone.

Conclusion

Understanding JavaScript hoisting and the execution context lifecycle prevents elusive runtime bugs and enables you to write clean, predictable asynchronous and synchronous code.

Published by Jayant Verma • Full-Stack Software Engineer & AI Architect