Search lands in PR-5.1 (Pagefind).

Explanation Beginner

Chapter 3 Updated

Hoisting in JavaScript

Why you can use variables and functions before declaring them — and why it sometimes breaks.

  • Full 13m
  • Revision 3m
  • Flow 2m

What hoisting really is

A consequence of Phase 1, not magic.

  • Not a physical move — declarations stay where they are in source.
  • Phase 1 (Memory Creation) scans the entire code and allocates memory.
  • Only declarations are hoisted — assignments stay in Phase 2.
  • Happens in every Execution Context (global and function scope).

var vs function declaration

The two classic behaviours.

  • var x = 10x hoisted as undefined; usable before the line.
  • function foo() {} → hoisted as entire function body; callable before the line.
  • Same-name collision → function wins during memory phase; later var assignment overwrites.
  • Duplicate function declarations → last one wins.

Function expressions + arrows

Treated as variables, not functions.

  • var fn = function() {} / var fn = () => {} → hoisted as undefined.
  • Calling before the assignment line → TypeError: is not a function.
  • Why TypeError? You’re invoking undefined().
  • Switch to let/const and the error becomes ReferenceError (TDZ).

let, const & class

Hoisted, but into the Temporal Dead Zone.

  • let / const / class are hoisted — but unreachable until the declaration line runs.
  • Accessing them in the TDZ → ReferenceError: Cannot access 'x' before initialization.
  • Different from undefined (var) and from “not defined” (never declared at all).
  • Classes share the TDZ rule — new Animal() before the class line throws too.

Three errors, three meanings

Which one fires, and why.

  • undefined — var was hoisted, no value yet. (console.log(x) before var x = 7.)
  • TypeError: is not a function — variable exists, but holds something non-callable.
  • ReferenceError: x is not defined — the identifier was never declared at all.
  • ReferenceError: Cannot access before initialization — let/const/class in TDZ.

Tricky corners

The bits interviewers love.

  • Named function expression — the name is usable inside the function only (good for recursion).
  • function a() {} after return inside a function still hoists — shadows globals.
  • Block-scoped function declarations are hoisted only within the block in modern strict mode.
  • console.log(fn) prints the whole function body — a live proof of Phase 1.

Comments

Comments are disabled in this environment. Set PUBLIC_GISCUS_REPO, PUBLIC_GISCUS_REPO_ID, and PUBLIC_GISCUS_CATEGORY_ID to enable.