How Does Hoisting Work in JavaScript: Variable and Function Declaration Behavior Explained
JavaScript hoisting moves variable and function declarations to the top of their containing scope during the compile phase, allowing var variables and function declarations to be referenced before their literal appearance in code, though let, const, and classes remain in a Temporal Dead Zone until their initialization line.
Understanding how hoisting works in JavaScript is essential for avoiding subtle bugs and writing predictable code. This concept, detailed in the src/questions/javascript-questions.md file of the h5bp/Front-end-Developer-Interview-Questions repository, describes the behavior where declarations are processed before any code execution begins. While often associated with variables, hoisting affects function declarations and class definitions differently depending on the declaration syntax used.
What Is Hoisting in JavaScript?
Hoisting is JavaScript's default behavior of moving declarations to the top of their containing scope during the compile phase, before any code is executed. Only the declaration is hoisted—the initialization stays where it appears in the source code.
This mechanism allows developers to reference certain identifiers before the lines where they appear, though the behavior varies significantly between var, let, const, function declarations, and class declarations.
How Different Declaration Types Are Hoisted
The h5bp/Front-end-Developer-Interview-Questions source code analysis reveals distinct hoisting behaviors for each declaration type.
var Variable Hoisting
Variables declared with var are hoisted to the top of their function or global scope and automatically initialized with undefined.
console.log(a); // → undefined
var a = 10;
console.log(a); // → 10
The variable name a is accessible before its assignment, but its value remains undefined until the initialization line executes.
let and const Temporal Dead Zone
Variables declared with let and const are hoisted to the top of their block scope, but they are not initialized. Instead, they enter the Temporal Dead Zone (TDZ)—a period between the start of the block and the declaration line where accessing the variable throws a ReferenceError.
// console.log(b); // ❌ ReferenceError: Cannot access 'b' before initialization
let b = 20;
console.log(b); // → 20
Function Declaration Hoisting
Function declarations are hoisted completely, meaning both the function name and definition are moved to the top of the enclosing scope. This allows calling the function before its literal appearance in the code.
greet(); // → "Hello!"
function greet() {
console.log('Hello!');
}
Function Expression and Arrow Function Limitations
Function expressions and arrow functions assigned to variables follow the hoisting rules of their declaration keyword. When using var, the variable is hoisted as undefined (not the function), and when using let or const, the variable enters the TDZ.
// shout(); // ❌ TypeError: shout is not a function
var shout = function() {
console.log('Hey!');
};
shout(); // → "Hey!"
With let:
// arrow(); // ❌ ReferenceError
let arrow = () => console.log('Arrow!');
arrow(); // → "Arrow!"
Class Declaration Hoisting
Like let and const, class declarations are hoisted to the top of their block scope but remain in the TDZ until the declaration line is evaluated. The class body is not executed until control flow reaches the class definition.
// const obj = new Person(); // ❌ ReferenceError
class Person {
constructor() { this.name = 'Alice'; }
}
const obj = new Person(); // Works after class is defined
console.log(obj.name); // → "Alice"
Why Hoisting Matters in JavaScript Development
Understanding hoisting behavior serves several practical purposes in the codebase analyzed in the h5bp/Front-end-Developer-Interview-Questions repository:
- Flexible code organization: Hoisting allows function declarations to appear after their call sites, enabling top-down reading of business logic with utility functions placed at the bottom of files.
- Error prevention: The TDZ for
let,const, andclasshelps catch early errors by throwingReferenceErrorexceptions when variables are accessed too soon, preventing the silentundefinedissues common withvar. - Avoiding undefined bugs: Misunderstanding
varhoisting can cause subtle bugs where variables appear to be "missing" but silently yieldundefined, making debugging difficult in complex applications.
Summary
- Hoisting moves declarations to the top of their scope during the compile phase, before code execution begins.
vardeclarations are hoisted and initialized withundefined, allowing access but returning an undefined value before the assignment line.let,const, andclassdeclarations are hoisted but remain in the Temporal Dead Zone (TDZ) until their initialization line, throwingReferenceErrorif accessed early.- Function declarations are fully hoisted with their definition, enabling invocation before the function appears in source code.
- Function expressions and arrow functions are only hoisted as variables (based on their declaration keyword), not as executable functions.
- The source material for these interview questions resides in
src/questions/javascript-questions.mdwithin the h5bp/Front-end-Developer-Interview-Questions repository.
Frequently Asked Questions
What is the Temporal Dead Zone (TDZ) in JavaScript?
The Temporal Dead Zone is the period between the start of a block scope and the actual declaration line for let, const, and class variables. During this phase, the variable name exists in the scope but cannot be accessed; attempting to do so throws a ReferenceError rather than returning undefined like var would.
Are function expressions hoisted in JavaScript?
Function expressions are not hoisted as executable functions. Only the variable declaration is hoisted—if declared with var, the variable is initialized as undefined; if declared with let or const, it enters the TDZ. The actual function assignment happens at runtime when the assignment line executes.
Why does typeof return undefined for hoisted var variables?
Before the initialization line executes, a hoisted var variable exists in the scope but holds the value undefined. Since undefined is a valid JavaScript type, typeof returns "undefined" rather than throwing an error, which can mask bugs where the variable appears to exist but contains no useful value.
Do let and const declarations get hoisted to the top of the scope?
Yes, let and const declarations are technically hoisted to the top of their block scope, but unlike var, they are not initialized. They enter the Temporal Dead Zone immediately at the start of the block, remaining inaccessible until the execution reaches the declaration line where they receive their initial value.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →