Difference between let, const and var
One-line answer: var is function-scoped and hoisted to undefined; let/const are block-scoped, hoisted but uninitialized (TDZ). let can be reassigned, const cannot (reference only).
Why this matters (beginner-friendly)
Choosing the right declaration prevents scope leaks, redeclaration bugs, and subtle hoisting issues especially in loops and async callbacks.
The concept in depth
- Scope:
var→ function scope;let/const→ block scope ({}). - Hoisting: All three are hoisted; only
varis initialized toundefined.let/constlive in the Temporal Dead Zone until their declaration line executes. - Redeclaration:
varallows redeclaration in the same scope;let/constdo not. - Reassignment:
varandletallow reassignment;constdoes not. For objects/arrays, the binding is constant but properties/elements may change.
Code examples
// Hoisting Difference
console.log(a); // undefined (var hoisted and initialized)
var a = 5;
console.log(b); // ReferenceError (TDZ)
let b = 5;
console.log(c); // ReferenceError (TDZ)
const c = 5;
// Block Scope vs function Scope
for(var i = 0; i < 3; i++) {
setTimeout(() => console.log("var i:", i),0);
};
// var i: 3,3,3
for(let j = 0; j < 3; j++) {
setTimeout(() => console.log("let j:", j), 0);
};
// let j: 0,1,2
// const immutable binding, mutable objects
const user = {{ name: "Alice" }};
user.name = "Bob"; // allowed
// user = {{}} -> TypeError: Assignment to constant variable
Common pitfalls & misconceptions
- Thinking
constmakes the object immutable (it only freezes the binding). - Using
varin loops with async callbacks causes late binding bugs. - Assuming
let/constaren't hoisted—they are, but remain uninitialized (TDZ).
Internal mechanics (how JS engines/spec handle this)
- Declarations form bindings in the current Lexical Environment.
varcreates a property on the Variable Environment and is set toundefinedat environment creation.let/constbindings exist but remain uninitialized until the declaration executes; access before that throws ReferenceError.
When to use / avoid
- Prefer
constby default; useletwhen you know the value will change. - Avoid
varin modern code unless maintaining legacy code.
Related topics
- Hoisting, TDZ, Scope & Closures, Binding of
this, Function vs Block scope
Practice questions
1. What happens when you access a `let` variable before its declaration?
-> It will give ReferenceError.
2. Why can you modify a `const` object's properties but not reassign it?
-> In javascript, the `const` keyword create an immutable binding rather than an immutable value.