Hoisting Basics

Course: JavaScript Intermediate

Lesson 2: Hoisting Basics

Level

Intermediate

Estimated Reading Time

10–15 minutes

Goal

By the end of this lesson, the learner will be able to:

  • Explain what hoisting is and how it affects var declarations and function declarations
  • Describe the temporal dead zone for let and const
  • Avoid bugs caused by accessing variables or functions before they are declared

Frontend Development Context

Hoisting is one of JavaScript's more surprising behaviors, and it catches developers off guard most often when reading or debugging older code. When a script loads, JavaScript processes declarations before running any code — so function declarations and var variables are available earlier than you might expect. This can make code work in ways that seem out of order.

In modern frontend development, you are more likely to encounter hoisting as a source of bugs than as a feature to rely on. Understanding it helps you read legacy code confidently, avoid writing code that depends on it accidentally, and understand error messages like "Cannot access before initialization" when they appear.

Explanation

Hoisting refers to the behavior where JavaScript moves certain declarations to the top of their scope during the compilation phase, before any code executes. Only the declarations are hoisted — not the initializations (the assigned values).

For var, the declaration is hoisted and initialized to undefined. This means you can reference a var variable before the line where you assign it, and JavaScript will not throw an error — it will just return undefined. This is a common source of confusion because the code appears to work but produces wrong values.

Function declarations are fully hoisted — both the declaration and the body. This means you can call a function before the line where it is defined and it will work correctly. This is why some developers write their function calls at the top of a file and function definitions below.

let and const are hoisted differently. Their declarations are recognized by JavaScript during the compilation phase, but they are not initialized until the code reaches the declaration line. The period between the start of the scope and the declaration line is called the temporal dead zone (TDZ). Accessing a let or const variable in the TDZ throws a ReferenceError.

Understanding the difference between var (hoisted and initialized to undefined), function declarations (fully hoisted), and let/const (hoisted but in TDZ) gives you a clear mental model of how JavaScript reads your code before running it.

Code Example

This example shows how hoisting affects var, function declarations, and let in different ways.

console.log(score);    // undefined — var is hoisted, but not yet assigned
var score = 10;
console.log(score);    // 10

// Function declarations are fully hoisted
greet("Alex");         // works — function body is available before its definition

function greet(name) {
  console.log(`Hello, ${name}!`);
}

// let is in the temporal dead zone before its declaration
try {
  console.log(level);  // ReferenceError
} catch (e) {
  console.log(e.message); // Cannot access 'level' before initialization
}
const level = "Intermediate";

Code Explanation

The first two lines demonstrate var hoisting. JavaScript sees var score during compilation and initializes it to undefined. When console.log(score) runs before the assignment, it gets undefined rather than an error. After the assignment line, score correctly holds 10.

greet("Alex") is called before the function definition appears in the file, and it works. Function declarations are fully hoisted — the entire function body is available from the start of the scope. This is a legitimate JavaScript feature, though relying on it heavily can make large files harder to read top to bottom.

The try/catch block around console.log(level) demonstrates the temporal dead zone. const level is recognized during compilation but not initialized yet. Accessing it before the declaration line throws a ReferenceError. The try/catch captures it so the rest of the script continues running.

Pattern Highlights

Positive Pattern: Declare variables at the top of their scope and define functions before you call them. This makes hoisting irrelevant in practice — your code reads in the same order it executes.

⚠️ Neutral Note: Function declarations are fully hoisted, so calling them before their definition is technically valid. In small files this may be fine, but in larger codebases it can make code harder to follow.

Negative Pattern: Do not rely on var hoisting to produce undefined as a way to check whether something has been set. This is a fragile pattern that let and const eliminate entirely.

Common Mistakes

Mistake 1: Expecting a var variable to hold its assigned value before assignment

Developers sometimes assume that if the variable is declared in the file, it already holds its value.

console.log(username); // undefined, not "Alice"
var username = "Alice";

The declaration is hoisted but the assignment is not. The variable exists but holds undefined until the assignment line executes.

Mistake 2: Treating function expressions like function declarations

Function expressions assigned to variables do not get fully hoisted.

sayHi(); // TypeError: sayHi is not a function

var sayHi = function () {
  console.log("Hi!");
};

var sayHi is hoisted and initialized to undefined. Calling undefined as a function throws a TypeError. Only function declarations using the function keyword at the statement level are fully hoisted.

Mistake 3: Accessing let or const before their declaration line

Expecting let to behave like var when accessed before its declaration.

console.log(theme); // ReferenceError: Cannot access 'theme' before initialization
let theme = "dark";

Unlike var, let and const do not initialize to undefined when hoisted. They remain in the temporal dead zone until the declaration line, and accessing them there throws a ReferenceError.

Quick Recap

  • var declarations are hoisted and initialized to undefined — accessing them before assignment gives undefined, not an error
  • Function declarations are fully hoisted — you can call them before their definition in the file
  • let and const are hoisted but not initialized — accessing them before their declaration throws a ReferenceError (temporal dead zone)
  • The safest practice is to declare everything before you use it, making hoisting behavior a non-issue

Ready to test your understanding? Take the quiz to reinforce what you learned.

© 2026 Ant Skillsv.26.07.07-23:01