Masterbook/Chapter 1• 2 min read
View Raw Code on GitHub

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 var is initialized to undefined. let/const live in the Temporal Dead Zone until their declaration line executes.
  • Redeclaration: var allows redeclaration in the same scope; let/const do not.
  • Reassignment: var and let allow reassignment; const does 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 const makes the object immutable (it only freezes the binding).
  • Using var in loops with async callbacks causes late binding bugs.
  • Assuming let/const aren't hoisted—they are, but remain uninitialized (TDZ).

Internal mechanics (how JS engines/spec handle this)

  • Declarations form bindings in the current Lexical Environment.
  • var creates a property on the Variable Environment and is set to undefined at environment creation.
  • let/const bindings exist but remain uninitialized until the declaration executes; access before that throws ReferenceError.

When to use / avoid

  • Prefer const by default; use let when you know the value will change.
  • Avoid var in 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.