# How Does Hoisting Work in JavaScript: Variable and Function Declaration Behavior Explained

> Understand JavaScript hoisting. Learn how variable and function declarations move to the top of the scope, enabling early code access and explaining the Temporal Dead Zone for let and const.

- Repository: [H5BP/Front-end-Developer-Interview-Questions](https://github.com/h5bp/Front-end-Developer-Interview-Questions)
- Tags: resource
- Published: 2026-03-05

---

**JavaScript hoisting moves variable and function declarations to the top of their containing scope during the compile phase, allowing `var` variables and function declarations to be referenced before their literal appearance in code, though `let`, `const`, and classes remain in a Temporal Dead Zone until their initialization line.**

Understanding how hoisting works in JavaScript is essential for avoiding subtle bugs and writing predictable code. This concept, detailed in the [`src/questions/javascript-questions.md`](https://github.com/h5bp/Front-end-Developer-Interview-Questions/blob/main/src/questions/javascript-questions.md) file of the **h5bp/Front-end-Developer-Interview-Questions** repository, describes the behavior where declarations are processed before any code execution begins. While often associated with variables, hoisting affects function declarations and class definitions differently depending on the declaration syntax used.

## What Is Hoisting in JavaScript?

Hoisting is JavaScript's default behavior of moving **declarations** to the top of their containing scope during the compile phase, before any code is executed. Only the declaration is hoisted—the **initialization** stays where it appears in the source code.

This mechanism allows developers to reference certain identifiers before the lines where they appear, though the behavior varies significantly between `var`, `let`, `const`, function declarations, and class declarations.

## How Different Declaration Types Are Hoisted

The h5bp/Front-end-Developer-Interview-Questions source code analysis reveals distinct hoisting behaviors for each declaration type.

### var Variable Hoisting

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

```javascript
console.log(a); // → undefined
var a = 10;
console.log(a); // → 10

```

The variable name `a` is accessible before its assignment, but its value remains `undefined` until the initialization line executes.

### let and const Temporal Dead Zone

Variables declared with `let` and `const` are hoisted to the top of their block scope, but they are not initialized. Instead, they enter the **Temporal Dead Zone (TDZ)**—a period between the start of the block and the declaration line where accessing the variable throws a `ReferenceError`.

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

```

### Function Declaration Hoisting

**Function declarations** are hoisted completely, meaning both the function name and definition are moved to the top of the enclosing scope. This allows calling the function before its literal appearance in the code.

```javascript
greet(); // → "Hello!"
function greet() {
  console.log('Hello!');
}

```

### Function Expression and Arrow Function Limitations

**Function expressions** and **arrow functions** assigned to variables follow the hoisting rules of their declaration keyword. When using `var`, the variable is hoisted as `undefined` (not the function), and when using `let` or `const`, the variable enters the TDZ.

```javascript
// shout(); // ❌ TypeError: shout is not a function
var shout = function() {
  console.log('Hey!');
};
shout(); // → "Hey!"

```

With `let`:

```javascript
// arrow(); // ❌ ReferenceError
let arrow = () => console.log('Arrow!');
arrow(); // → "Arrow!"

```

### Class Declaration Hoisting

Like `let` and `const`, **class declarations** are hoisted to the top of their block scope but remain in the TDZ until the declaration line is evaluated. The class body is not executed until control flow reaches the class definition.

```javascript
// const obj = new Person(); // ❌ ReferenceError
class Person {
  constructor() { this.name = 'Alice'; }
}
const obj = new Person(); // Works after class is defined
console.log(obj.name); // → "Alice"

```

## Why Hoisting Matters in JavaScript Development

Understanding hoisting behavior serves several practical purposes in the codebase analyzed in the h5bp/Front-end-Developer-Interview-Questions repository:

- **Flexible code organization**: Hoisting allows function declarations to appear after their call sites, enabling top-down reading of business logic with utility functions placed at the bottom of files.
- **Error prevention**: The TDZ for `let`, `const`, and `class` helps catch early errors by throwing `ReferenceError` exceptions when variables are accessed too soon, preventing the silent `undefined` issues common with `var`.
- **Avoiding undefined bugs**: Misunderstanding `var` hoisting can cause subtle bugs where variables appear to be "missing" but silently yield `undefined`, making debugging difficult in complex applications.

## Summary

- **Hoisting** moves declarations to the top of their scope during the compile phase, before code execution begins.
- **`var`** declarations are hoisted and initialized with `undefined`, allowing access but returning an undefined value before the assignment line.
- **`let`**, **`const`**, and **`class`** declarations are hoisted but remain in the **Temporal Dead Zone (TDZ)** until their initialization line, throwing `ReferenceError` if accessed early.
- **Function declarations** are fully hoisted with their definition, enabling invocation before the function appears in source code.
- **Function expressions** and **arrow functions** are only hoisted as variables (based on their declaration keyword), not as executable functions.
- The source material for these interview questions resides in [`src/questions/javascript-questions.md`](https://github.com/h5bp/Front-end-Developer-Interview-Questions/blob/main/src/questions/javascript-questions.md) within the h5bp/Front-end-Developer-Interview-Questions repository.

## Frequently Asked Questions

### What is the Temporal Dead Zone (TDZ) in JavaScript?

The Temporal Dead Zone is the period between the start of a block scope and the actual declaration line for `let`, `const`, and `class` variables. During this phase, the variable name exists in the scope but cannot be accessed; attempting to do so throws a `ReferenceError` rather than returning `undefined` like `var` would.

### Are function expressions hoisted in JavaScript?

Function expressions are not hoisted as executable functions. Only the variable declaration is hoisted—if declared with `var`, the variable is initialized as `undefined`; if declared with `let` or `const`, it enters the TDZ. The actual function assignment happens at runtime when the assignment line executes.

### Why does typeof return undefined for hoisted var variables?

Before the initialization line executes, a hoisted `var` variable exists in the scope but holds the value `undefined`. Since `undefined` is a valid JavaScript type, `typeof` returns `"undefined"` rather than throwing an error, which can mask bugs where the variable appears to exist but contains no useful value.

### Do let and const declarations get hoisted to the top of the scope?

Yes, `let` and `const` declarations are technically hoisted to the top of their block scope, but unlike `var`, they are not initialized. They enter the Temporal Dead Zone immediately at the start of the block, remaining inaccessible until the execution reaches the declaration line where they receive their initial value.