Hoisting is a behavior in JavaScript where variable and function declarations are moved to the top of their scope (global or local) during the compilation phase. This means that variables and functions can be used before they are declared, without causing a runtime error.

However, only the declarations are hoisted, not the assignments. This behavior applies to both var, let, const variables, and function declarations, but with slight differences between them.


How Hoisting Works with var

When you declare a variable using var, the declaration is hoisted to the top of its scope, but the assignment remains in place.

Example 1: var

console.log(a); // Output: undefined
var a = 10;
console.log(a); // Output: 10

Explanation:

  1. During the compilation phase, JavaScript hoists the var a; declaration to the top.
  2. The assignment (a = 10) is not hoisted. So, when we try to access a before the assignment, we get undefined.

Behind the scenes, the code above behaves as:

var a;    // Declaration hoisted
console.log(a); // Output: undefined
a = 10;   // Assignment happens here
console.log(a); // Output: 10

Hoisting with let and const

Variables declared using let and const are also hoisted, but they are placed in a temporal dead zone (TDZ) from the start of the block until the declaration is encountered. This means that accessing them before their declaration causes a ReferenceError.

Example 2: let and const

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

In this case:

  • The let declaration is hoisted, but the variable is not initialized, so accessing it before the declaration throws a ReferenceError.

The same behavior applies to const, except that variables declared with const must also be initialized at the time of declaration.


Hoisting with Function Declarations

Function declarations are fully hoisted, meaning both the function declaration and its body are available before the line where they are declared.

Example 3: Function Declaration

greet(); // Output: Hello, world!

function greet() {
  console.log("Hello, world!");
}

The code behaves as:

function greet() { // Hoisted to the top
  console.log("Hello, world!");
}
greet(); // Output: Hello, world!

Hoisting with Function Expressions

In the case of function expressions (using var, let, or const), only the variable declaration is hoisted, not the function assignment.

Example 4: Function Expression with var

console.log(sayHello); // Output: undefined
var sayHello = function() {
  console.log("Hello!");
};
sayHello(); // Output: Hello!
  • Here, only the declaration var sayHello; is hoisted, so calling sayHello before the assignment gives undefined.

Summary of Hoisting Rules:

  1. var:
  • Declaration is hoisted, but not the assignment.
  • Accessing before assignment results in undefined.
  1. let / const:
  • Declaration is hoisted, but not initialized.
  • Accessing before declaration results in a ReferenceError.
  1. Function Declarations:
  • Entire function (including body) is hoisted.
  • Can be called before its declaration.
  1. Function Expressions:
  • Only the variable declaration is hoisted, not the function assignment.

Visualizing the Temporal Dead Zone (TDZ)

{
  console.log(x); // ReferenceError
  let x = 5;
}
  • The block above demonstrates that the let variable x is hoisted, but it is in the TDZ until the line let x = 5 is executed.

Why Hoisting Matters?

  1. Prevents Runtime Errors: Hoisting allows you to use functions and variables before their declaration in some cases.
  2. Encourages Best Practices: Understanding hoisting encourages developers to structure code carefully, especially with modern constructs like let and const.
  3. Avoids Confusion: Knowing that let and const variables are hoisted (but not initialized) helps avoid ReferenceErrors.

Hoisting is a crucial concept for understanding how JavaScript code is interpreted and helps you avoid subtle bugs!

Tagged in:

,