Question
JavaScript let vs var: Scope, Hoisting, and When to Use Each
Question
ECMAScript 6 introduced the let declaration keyword.
I have heard that it is described as a local variable, but I am still not fully sure how it behaves differently from the var keyword.
What are the differences between let and var in JavaScript? When should let be used instead of var?
Short Answer
By the end of this page, you will understand how let and var differ in scope, hoisting, redeclaration, and global behavior in JavaScript. You will also learn why modern JavaScript usually prefers let and const over var, and how to avoid common bugs caused by var.
Concept
let and var are both used to declare variables in JavaScript, but they follow different rules.
The biggest difference is scope:
varis function-scopedletis block-scoped
A block is any code inside curly braces {} such as an if, for, or while statement.
if (true) {
var a = 10;
let b = 20;
}
console.log(a); // 10
console.log(b); // ReferenceError
Here, a is still available outside the if block because var ignores block scope. But b only exists inside the block because respects block scope.
Mental Model
Think of var as a label attached to an entire room, while let is a label attached to a specific box inside the room.
- With
var, if you declare a variable anywhere in a function, it is available across the whole function. - With
let, the variable only exists inside the exact block where you created it.
Another way to think about it:
varis like a note written on the wall of the whole function.letis like a sticky note placed on one section only.
This is why let gives you tighter control. Variables stay closer to where they are actually used.
Syntax and Examples
Basic syntax
var name = "Alice";
let age = 25;
Both declare variables, but they behave differently.
Scope example
function test() {
if (true) {
var city = "Paris";
let country = "France";
}
console.log(city); // "Paris"
console.log(country); // ReferenceError
}
Why this happens
cityusesvar, so it belongs to the whole functiontestcountryuseslet, so it exists only inside theifblock
Loop example
Step by Step Execution
Consider this example:
function demo() {
console.log(a);
// console.log(b);
var a = 1;
let b = 2;
if (true) {
var aInside = "var value";
let bInside = "let value";
}
console.log(a); // 1
console.log(b); // 2
console.log(aInside); // "var value"
// console.log(bInside); // ReferenceError
}
demo();
What happens step by step
- The function
demostarts running. - JavaScript sees
var aand hoists it, initializing it toundefined. - JavaScript also hoists
let b, but does not initialize it yet. console.log(a)prints .
Real World Use Cases
let is useful whenever a variable should only exist in a small area of code.
Common real-world examples
Inside loops
for (let index = 0; index < items.length; index++) {
console.log(items[index]);
}
Each iteration gets the correct index.
Temporary calculation values
function calculateTotal(price, taxRate) {
let tax = price * taxRate;
let total = price + tax;
return total;
}
The variables only exist where they are needed.
Conditional logic
if (user.isAdmin) {
let message = "Access granted";
console.log(message);
}
message does not leak outside the block.
API or form validation code
Real Codebase Usage
In real projects, developers usually follow this pattern:
- use
constby default - use
letwhen reassignment is needed - avoid
var
Typical pattern
const apiUrl = "/users";
let retries = 0;
while (retries < 3) {
retries++;
}
Why teams avoid var
Fewer scope bugs
let keeps variables inside the block where they are used.
Safer refactoring
If code is moved into an if block or loop, let is less likely to affect surrounding code unexpectedly.
Better loop behavior
let works naturally with asynchronous callbacks inside loops.
Common patterns in codebases
Guard clauses
function () {
(!user) {
;
}
name = user..();
.(name);
}
Common Mistakes
1. Assuming var is block-scoped
Broken code:
if (true) {
var message = "hello";
}
console.log(message); // still works
Why it is a problem:
You may expect message to disappear after the block, but it does not.
How to avoid it:
Use let when you want block scope.
if (true) {
let message = "hello";
}
console.log(message); // ReferenceError
2. Using a let variable before declaring it
Broken code:
console.log(total);
let total = 100;
Why it is a problem:
is hoisted but not initialized before the declaration line.
Comparisons
| Feature | var | let |
|---|---|---|
| Scope | Function scope | Block scope |
| Hoisted | Yes | Yes |
| Accessible before declaration | Yes, as undefined | No, causes ReferenceError |
| Redeclaration in same scope | Allowed | Not allowed |
| Creates global object property at top level | Usually yes | No |
| Loop iteration binding | Shared | New binding per iteration |
| Recommended for modern code | Usually no | Yes |
Cheat Sheet
var x = 1;
let y = 2;
Key rules
varis function-scopedletis block-scopedvarcan be redeclared in the same scopeletcannot be redeclared in the same scopevaris hoisted and initialized toundefinedletis hoisted but stays in the temporal dead zone until declared
Scope example
if (true) {
var a = 1;
let b = 2;
}
console.log(a); // 1
console.log(b); // ReferenceError
Hoisting example
console.(x);
x = ;
.(y);
y = ;
FAQ
Is let always better than var in JavaScript?
In modern JavaScript, yes for most cases. let is safer because it uses block scope and avoids many bugs caused by var.
Why does var print undefined before declaration?
Because var is hoisted and initialized with undefined before the code runs.
Why does let throw a ReferenceError before declaration?
Because let exists in the temporal dead zone until the declaration line is reached.
Should I still learn var?
Yes. You will still see it in older codebases, interview questions, and legacy tutorials.
What should I use in modern JavaScript: var, let, or const?
Use const by default, let when reassignment is needed, and avoid unless you are working with older code.
Mini Project
Description
Build a small loop-based logging script that shows the practical difference between var and let in asynchronous code. This project demonstrates one of the most common real-world bugs caused by var: every callback using the same final loop value.
Goal
Create a script that schedules delayed log messages and observe how var and let produce different results inside a loop.
Requirements
- Create one loop using
varand one loop usinglet - Use
setTimeoutinside both loops - Log the loop variable from each callback
- Show that
varlogs the final value repeatedly - Show that
letlogs each iteration value correctly
Keep learning
Related questions
Deep Cloning Objects in JavaScript: Methods, Trade-offs, and Best Practices
Learn how to deep clone objects in JavaScript, compare structuredClone, JSON methods, and recursive approaches with examples.
Get Screen, Page, and Browser Window Size in JavaScript
Learn how to get screen size, viewport size, page size, and scroll position in JavaScript across major browsers with clear examples.
How JavaScript Closures Work: A Beginner-Friendly Guide
Learn how JavaScript closures work with simple explanations, examples, common mistakes, and practical use cases for real code.