Compile Ready
Module 4 · Execution Context & Hoisting

The Memory (Creation) Phase

Intermediate11m read10m practice21m total
Creation PhaseHoistingTDZDeclarations

Introduction

Before JavaScript executes your first line, it performs a memory phase for the current execution context. The engine scans declarations, creates bindings, and decides their initial state. This is where the behaviors called hoisting and temporal dead zone are born.

The key is precise: declarations are prepared early, but assignments and most expressions still wait for the execution phase.

Why This Matters

Most output-prediction bugs are creation-phase bugs. If you can build the memory table before executing a snippet, you can predict undefined, ReferenceError, TypeError, callable function declarations, and shadowing behavior without guessing.

Theory

What the engine prepares

During creation, JavaScript builds an environment record for the context. It does not run business logic yet; it prepares names.

Declaration formCreation-phase stateWhat happens when read before the line?
var xBinding exists and is initialized to undefinedReturns undefined.
function f() {}Binding exists and points to the function objectCallable before its declaration line.
let xBinding exists but is uninitializedThrows ReferenceError due to TDZ.
const xBinding exists but is uninitializedThrows ReferenceError due to TDZ.
class C {}Binding exists but is uninitializedThrows ReferenceError due to TDZ.
var f = function () {}f exists as undefined; function value assigned laterCalling before assignment throws TypeError.

Parameters are initialized too

When a function context is created, parameter bindings are initialized before the body runs. Default parameters are evaluated left to right, which creates its own TDZ-like traps: an earlier default cannot read a later parameter.

Function declarations are special

A function declaration is available as a function object during creation. That is why sayHi() can work before the declaration appears in source. A function expression assigned to var does not get this treatment; only the variable binding is prepared.

let and const are hoisted, but not usable

A common incorrect answer is that let and const are not hoisted. They are hoisted in the sense that the binding is created at scope entry. They are just not initialized until execution reaches the declaration. The interval before that line is the temporal dead zone.

Mental workflow for interviews

  1. Draw a memory table for the current scope.
  2. Fill var with undefined.
  3. Fill function declarations with function objects.
  4. Mark let, const, and class as TDZ.
  5. Only then execute statements top to bottom.

Visual Diagrams

Creation-phase memory table
Code
  console.log(a)
  var a = 1
  let b = 2
  function run() {}

Creation phase
  a   -> undefined
  b   -> uninitialized TDZ
  run -> function object

Execution phase later performs the assignments a = 1 and b = 2

The declaration kind determines the initial binding state.

Function expression with var
Creation phase
  greet -> undefined

Execution phase
  greet() before assignment -> TypeError
  greet = function object
  greet() after assignment  -> works

The variable is hoisted; the function expression value is not.

Code Examples

Build the memory table first

Before execution, count exists as undefined, show is callable, and name is present but unavailable in the TDZ.

Loading…

Function declaration vs function expression

Only the declaration is initialized to a function object during creation. The expression assignment happens later.

Loading…

Playground

Loading editor…
Console

Press Run to execute the code and see output here.

Output Prediction

Predict the output #1

javascript
1console.log(score);
2var score = 10;
3console.log(score);

Predict the output #2

javascript
1sayHi();
2
3try {
4 greet();
5} catch (error) {
6 console.log(error.name);
7}
8
9function sayHi() {
10 console.log('hi');
11}
12
13var greet = function () {
14 console.log('hello');
15};
16
17greet();

Predict the output #3

javascript
1try {
2 console.log(name);
3} catch (error) {
4 console.log(error.name);
5}
6
7let name = 'Ada';
8console.log(name);

Coding Exercises

Classify declaration creation states

Medium

Implement describeCreationPhase(declarations). Each item has { name, kind }, where kind is 'var', 'function', 'let', 'const', or 'class'. Return strings describing the binding's creation-phase state, such as 'count -> undefined' or 'User -> TDZ'.

Interview Questions

1What happens in the creation phase of an execution context?

The engine creates the environment record for the scope. It registers declarations, initializes var bindings to undefined, stores function declarations as function objects, creates let/const/class bindings in an uninitialized TDZ state, sets up the scope chain, and establishes the this binding. It does not execute assignments or function expressions yet.

Asked at:GoogleAmazonMicrosoft

Follow-ups

  • Why can function declarations be called before their source line?
  • Are let and const hoisted?
2Why does calling a var-assigned function expression before its line throw TypeError instead of ReferenceError?

Because the var binding exists and is initialized to undefined during creation, so the name resolves successfully. The error happens because execution tries to call the current value, undefined, as a function. That is a TypeError. A missing name would be ReferenceError; a TDZ name would also be ReferenceError.

Asked at:MetaNetflix

Quiz

1. What is the creation-phase state of `var total`?

2. Which declaration is callable before its source line executes?

Summary

  • The memory phase creates bindings before statements run.
  • `var` starts as `undefined`; function declarations start as function objects.
  • `let`, `const`, and `class` bindings exist but are uninitialized in the TDZ.
  • Function expressions, arrow functions assigned to variables, and assignments happen during execution, not creation.

Cheat Sheet

Creation phase table:

var -> undefined

function declaration -> function object

let / const / class -> TDZ until declaration executes

var f = function () {} -> f is undefined; function value assigned later

Interview process: make the memory table first, then execute line by line.