One of the most common JavaScript interview questions is:
What is hoisting in JavaScript?
Most developers answer:
Variables and functions are moved to the top.
While this explanation works for beginners, it is not technically accurate.
Interviewers often ask deeper questions:
- Is code actually moved?
- Why does
varbehave differently fromletandconst? - What is the Temporal Dead Zone?
- How are functions hoisted?
- How does hoisting relate to execution contexts?
Let's understand hoisting from first principles.
1. What is Hoisting?#
Hoisting is JavaScript's behavior of making declarations available before their actual position in the code during the creation phase of execution.
This allows code like:
console.log(name);
var name = "John";
to execute without throwing a reference error.
Output:
undefined
This surprises many developers.
The Common Misconception#
Many tutorials explain hoisting as:
JavaScript moves code to the top
Example:
console.log(name);
var name = "John";
becomes:
var name;
console.log(name);
name = "John";
This mental model helps beginners.
However:
JavaScript does NOT physically move code.
Instead, hoisting happens during execution context creation.
2. Under the Hood: Execution Context#
Before JavaScript executes code, it creates an:
Execution Context
This process has two phases:
1. Creation Phase
2. Execution Phase
Creation Phase#
JavaScript scans the code and registers:
- Variables
- Functions
- Parameters
Memory is allocated.
Execution Phase#
JavaScript executes code line by line.
Visual Representation#
Creation Phase
↓
Allocate Memory
↓
Execution Phase
↓
Run Code
Hoisting occurs during:
Creation Phase
3. Variable Hoisting with var#
Example:
console.log(name);
var name = "John";
During creation phase:
name = undefined;
During execution:
console.log(name);
Output:
undefined
Then:
name = "John";
Why Doesn't It Throw an Error?#
Because:
var name;
already exists in memory.
Its initial value is:
undefined;
Visual Example#
Code:
console.log(name);
var name = "John";
Creation Phase:
name = undefined;
Execution Phase:
console.log(undefined);
name = "John";
Output:
undefined
4. Function Hoisting & Declaration vs. Expression#
Function declarations are fully hoisted.
Example:
greet();
function greet() {
console.log("Hello");
}
Output:
Hello
Why?
Because the entire function is stored during creation.
Creation phase:
greet = function () {
console.log("Hello");
};
Function Declaration vs Function Expression#
Interviewers love this question.
Example:
greet();
var greet = function () {
console.log("Hello");
};
Output:
TypeError
Why?#
Creation phase:
greet = undefined;
Execution:
greet();
Equivalent to:
undefined();
Which causes:
TypeError: greet is not a function
Function Declaration Example#
greet();
function greet() {
console.log("Hello");
}
Output:
Hello
Because the entire function is hoisted.
Function Expression Example#
greet();
const greet = function () {
console.log("Hello");
};
Output:
ReferenceError
This leads us to:
let and const
5. Block Scope Hoisting: let and const#
Many developers believe:
let is not hoisted
This is incorrect.
Example:
console.log(age);
let age = 25;
Output:
ReferenceError
Is let Hoisted?#
Yes.
During creation phase:
age;
is registered.
However:
It remains uninitialized.
This creates the:
Temporal Dead Zone (TDZ)
6. The Temporal Dead Zone (TDZ)#
The Temporal Dead Zone is the period between:
Variable Creation
and
Variable Initialization
Example:
console.log(age);
let age = 25;
Timeline:
Creation Phase
↓
age exists
Execution Begins
↓
TDZ
let age = 25
↓
Initialized
Accessing it during TDZ causes:
ReferenceError
Hoisting with const#
const behaves similarly to let.
Example:
console.log(PI);
const PI = 3.14;
Output:
ReferenceError
Reason:
Temporal Dead Zone
7. Side-by-Side Comparison: var vs. let vs. const#
Consider:
console.log(a);
console.log(b);
console.log(c);
var a = 1;
let b = 2;
const c = 3;
Output:
undefined
ReferenceError
ReferenceError
Comparison Table#
| Declaration | Hoisted | Initialized |
|---|---|---|
| var | ✅ Yes | ✅ undefined |
| let | ✅ Yes | ❌ No |
| const | ✅ Yes | ❌ No |
| function declaration | ✅ Yes | ✅ Function |
| function expression | Depends on variable declaration | Depends on variable declaration |
Interview Question#
What is the output?
var x = 1;
function test() {
console.log(x);
var x = 2;
}
test();
Answer#
Output:
undefined
Why?
Creation phase inside function:
var x = undefined;
Execution:
console.log(x);
Output:
undefined
Then:
x = 2;
Another Interview Question#
What is the output?
let x = 1;
function test() {
console.log(x);
let x = 2;
}
test();
Answer#
Output:
ReferenceError
Because:
x;
is inside the TDZ.
Nested Scope Example#
var name = "Global";
function demo() {
console.log(name);
var name = "Local";
}
demo();
Output:
undefined
Local variable hoisting shadows the global variable.
8. Class Hoisting Rules#
Classes are also hoisted.
Example:
const user = new User();
class User {}
Output:
ReferenceError
Why?
Classes behave similarly to:
let;
They exist in a Temporal Dead Zone until initialized.
9. Common Interview Q&A#
Is JavaScript Moving Code to the Top?#
No.
JavaScript creates bindings during the creation phase of execution contexts.
Are let and const Hoisted?#
Yes.
They are hoisted but remain uninitialized until execution reaches their declaration.
What Causes the Temporal Dead Zone?#
Accessing a hoisted variable before it has been initialized.
Why Does var Return Undefined?#
Because var is initialized with:
undefined;
during the creation phase.
Why Are Function Declarations Callable Before Definition?#
Because the entire function is stored in memory during the creation phase.
Real Frontend Example#
Consider:
function initializeApp() {
loadUser();
}
function loadUser() {
console.log("Loading user...");
}
initializeApp();
This works because function declarations are hoisted.
Senior-Level Interview Answer#
Hoisting is JavaScript's behavior of creating bindings for variables and functions during the creation phase of an execution context before code execution begins. Variable declarations using
varare hoisted and initialized withundefined, whileletandconstare hoisted but remain uninitialized inside the Temporal Dead Zone until their declaration is evaluated. Function declarations are fully hoisted, allowing them to be invoked before their definition appears in the source code. Hoisting is not the physical movement of code but a consequence of how JavaScript builds execution contexts.
Common Interview Mistakes#
❌ "JavaScript moves code to the top."
Correct:
JavaScript creates bindings during
the creation phase.
❌ "let and const are not hoisted."
Correct:
They are hoisted but remain
uninitialized.
❌ "Function expressions are hoisted like functions."
Correct:
Only the variable declaration is hoisted.
❌ "TDZ means the variable doesn't exist."
Correct:
The variable exists but cannot
be accessed yet.
Hoisting Summary#
| Feature | var | let | const |
|---|---|---|---|
| Hoisted | ✅ | ✅ | ✅ |
| Initialized During Creation | ✅ undefined | ❌ | ❌ |
| Temporal Dead Zone | ❌ | ✅ | ✅ |
| Reassignment Allowed | ✅ | ✅ | ❌ |
Key Takeaways#
- Hoisting Myth: JavaScript does not move code lines; the compiler registers variables and functions during the creation phase.
- var Sizing: Declaring variables with
varinitializes them asundefined, avoiding compile-time ReferenceErrors. - let & const TDZ: Block-scoped variables are hoisted but reside in the Temporal Dead Zone (TDZ) until their declaration line is evaluated.
- Functions: Function declarations are hoisted fully, making them callable before definition; function expressions are not.