AceDevHub
Control Flow & FunctionsFree

Scope, Closures, and Hoisting

Understand lexical scope, closures that remember variables, hoisting rules, and the temporal dead zone — the core of JavaScript interviews.

IntermediateFreeScope

Scope and closures are the bridge between syntax and interview questions. If you can explain why a callback still sees a variable after its outer function finished, you understand half of JavaScript's power and half of its memory behavior. This lesson ties together lexical scope, hoisting, TDZ, and practical closure patterns you will use in real features.

Lexical scope — where variables live

Scope is determined by where code is written (lexical scope), not where it runs. Inner blocks and functions can read outer variables; outer scopes cannot see inner declarations. Each function invocation creates a new scope object for its locals — that is why two calls to the same function do not share local let variables unless you intentionally close over shared outer state.

lexical-scope.js
Loading editor…
Outputconsole
Learn AceDevHub — Ship faster

Closures — functions that remember their environment

A closure forms when a function is defined inside another function and the inner function references variables from the outer scope. The inner function keeps those references alive even after the outer call returns — the outer variables live on the heap as long as any inner function can still run. Closures enable private state, partial application, and React hooks remembering previous renders.

closure-counter.js
Loading editor…
Outputconsole
11
12
11
11

Practical closure — once-style function

The counter factory is the canonical closure: createCounter's local count is not reachable from outside, but returned methods close over it. That is module-pattern privacy before ES modules — and the same idea behind let in a loop creating per-iteration bindings for async callbacks.

closure-once.js
Loading editor…
Outputconsole
Connecting to database...

Hoisting — declarations move, assignments do not

The once wrapper demonstrates why closures matter in production: called and result persist between invocations without global variables. Event listeners, debouncers, and singleton initializers use the same pattern — wrap mutable state in an outer function, expose only the controlled inner function.

hoisting.js
Loading editor…
Outputconsole
Hi
undefined
ES2024

Temporal Dead Zone (TDZ)

Hoisting is compile-time binding registration, not physical line movement. Function declarations hoist fully. var hoists name with undefined value until assignment executes. let/const hoist but enter the temporal dead zone — the name exists but access throws until the declaration line runs, preventing use-before-init bugs.

From the start of the block until the let or const line executes, the binding exists but cannot be accessed — that region is the TDZ. It prevents the var-era bug of using variables before initialization.

tdz.js
Loading editor…
Outputconsole
42
undefined

Scope chain lookup

The example below demonstrates "Scope chain lookup" in runnable form. Read the comment lines first — they map each step to the mental model from earlier sections, then trace execution top to bottom as the engine would.

scope-chain.js
Loading editor…
Outputconsole
inner
outer
global

Chapter 2 checkpoint

Scope chain lookup walks outward from inner to outer until it finds a matching name or hits global. Shadowing (inner const level hiding outer level) is legal but should be used sparingly — reuse the same name only when it genuinely refers to the same concept at different layers.

You can compare values safely, branch with conditionals, iterate collections, write functions three ways, and explain closures and hoisting — the vocabulary of every JavaScript interview. Chat 3 moves into arrays, objects, destructuring, prototypes, and modules.

  1. 1=== for daily checks; Object.is for NaN and -0
  2. 2Closures = function + remembered outer variables
  3. 3let/const have TDZ; var hoists as undefined
  4. 4Each for (let i ...) iteration creates its own closure binding
  5. 5Next: arrays, objects, and destructuring patterns