Hoisting in JavaScript
Hoisting
JavaScript behaves differently from many other programming languages.
One of its unique behaviors is called hoisting.
Hoisting affects how variables and functions are created.
It can confuse beginners, and even experienced developers sometimes forget how it works.
In this article, you will learn:
what hoisting means
how variable hoisting works
how function hoisting works
common mistakes
the “correct mental model” to avoid bugs
Let’s start with the definition.
What Is Hoisting?
Hoisting means JavaScript moves variable and function declarations to the top of their scope before code runs.
This does not mean your code is rearranged.
It means JavaScript creates memory for these declarations during the “creation phase” of execution.
So you can use some variables and functions even before they appear in your code.
Function Hoisting
Function declarations are fully hoisted.
This means you can call the function before you write it.
Example:
sayHello(); // Output: Hello!
function sayHello() {
console.log("Hello!");
}
This works because during hoisting, JavaScript stores the entire function in memory.
When is this useful?
It allows you to write code in any order.
You can place helper functions at bottom and main logic at the top.
Variable Hoisting
Variables behave differently depending on whether you use:
varletconst
Let’s look at each one.
1. Hoisting with var
Variables declared with var are hoisted but initialized with undefined.
Example:
console.log(a); // undefined
var a = 10;
The variable exists at the top of the scope, but it does not have a value yet.
2. Hoisting with let and const
let and const are also hoisted, but they are not initialized.
They are placed in something called the Temporal Dead Zone (TDZ) until the line where they are declared.
Example:
console.log(x); // ReferenceError
let x = 5;
Why the error?
Because x exists, but JavaScript does not allow you to use it before declaration.
Same with const:
console.log(y); // ReferenceError
const y = 20;
The Temporal Dead Zone (TDZ)
The TDZ is the region from the start of the scope to the line where the variable is declared.
You cannot access the variable in this zone.
Correct Mental Model for Hoisting
Think of hoisting like this:
During the Memory Creation Phase:
Function declarations → stored as full functions
var→ stored asundefinedletandconst→ allocated but not initialized (TDZ)
During the Execution Phase:
Code runs line by line
Values are assigned
TDZ ends at the declaration line
Function Declaration vs Function Expression
Hoisting behaves differently depending on the syntax.
1. Function Declarations (fully hoisted)
greet(); // Works!
function greet() {
console.log("Hello!");
}
2. Function Expressions (NOT fully hoisted)
Using var:
greet(); // TypeError: greet is not a function
var greet = function () {
console.log("Hello!");
};
Why?
var greet becomes undefined during hoisting.
So at the time of the call, greet is undefined, not a function.
3. Arrow Functions
Arrow functions behave like function expressions.
Using let:
greet(); // ReferenceError
let greet = () => {
console.log("Hello!");
};
They stay in the Temporal Dead Zone until declared.
Common Mistakes with Hoisting
Mistake 1: Using variables before declaring them
console.log(score); // ReferenceError
let score = 100;
Mistake 2: Assuming var is safe because it does not throw error
console.log(a); // undefined, not error
var a = 1;
This often causes silent bugs.
Mistake 3: Assuming all functions are hoisted the same way
run(); // Error
let run = function () {};
Function expressions are not hoisted like declarations.
Best Practices to Avoid Hoisting Bugs
✔ Always declare variables at the top of the scope
✔ Use let and const instead of var
✔ Write functions before calling them (even though not required)
✔ Avoid mixing declarations and usage in confusing order
✔ Use const for functions when possible
These practices make your code predictable and easier to read.
Summary
| Item | Hoisted? | Initialized? | Usable before declaration? |
var | Yes | undefined | Yes (but unsafe) |
let | Yes | No (TDZ) | No |
const | Yes | No (TDZ) | No |
| Function Declaration | Yes | Yes (full function) | Yes |
| Function Expression | Yes (variable only) | No | No |
| Arrow Function | Yes (variable only) | No | NoHoisting in JavaScript: A Simple Guide for Beginners |