How variables work in JS
Part 1: var — the old way
var was the only way to declare variables before ES6 (2015). It has two behaviours that cause bugs: it's function-scoped (not block-scoped) and it's hoisted as undefined.
var ignores block scope
javascript
if (true) {
var x = 10; // NOT block-scoped!
}
console.log(x); // 10 — var leaked out of the if block
for (var i = 0; i < 3; i++) {}
console.log(i); // 3 — i leaked out of the for loop!var can be re-declared (another source of bugs)
javascript
var name = "Arjun";
var name = "Kumar"; // ✅ No error — silently overwrites!
console.log(name); // Kumar
// This means you can accidentally overwrite a variable
// declared elsewhere in the same function — no warning given.Part 2: let — the modern default
let was introduced in ES6 to fix var's problems. It is block-scoped, cannot be re-declared, and is in the TDZ before its declaration.
let respects block scope
javascript
if (true) {
let y = 20; // block-scoped
}
console.log(y); // ❌ ReferenceError: y is not defined
for (let i = 0; i < 3; i++) {}
console.log(i); // ❌ ReferenceError — i stays inside the looplet cannot be re-declared
javascript
let score = 100;
let score = 200; // ❌ SyntaxError: Identifier 'score' already declared
// But it CAN be reassigned:
let age = 22;
age = 23; // ✅ Fine — reassignment is different from re-declarationPart 3: const — for values that don't change
const is like let but the binding cannot be reassigned. Use it as your default — it forces you to be intentional when a value needs to change.
const prevents reassignment
javascript
const PI = 3.14159;
PI = 3; // ❌ TypeError: Assignment to constant variable
const country = "India";
country = "USA"; // ❌ TypeError
// Must be initialised at declaration:
const x; // ❌ SyntaxError: Missing initializer in const declarationconst with objects — the binding is const, not the contents
const prevents reassigning the variable, but if it holds an object or array, you can still change the contents of that object.
javascript
const user = { name: "Arjun", age: 22 };
user.age = 23; // ✅ modifying a property — allowed!
user.city = "Chennai"; // ✅ adding a property — allowed!
user = {}; // ❌ TypeError: reassigning the binding — not allowed
// Same with arrays:
const nums = [1, 2, 3];
nums.push(4); // ✅ [1, 2, 3, 4]
nums = [5, 6]; // ❌ TypeErrorQuick comparison table
javascript
// var let const
// Scope: function block block
// Hoisting: undefined TDZ error TDZ error
// Re-declare: ✅ yes ❌ no ❌ no
// Reassign: ✅ yes ✅ yes ❌ no
// Use today: ❌ avoid ✅ default ✅ preferred
// Rule of thumb:
// 1. Use const by default
// 2. Use let only when you know the value will change
// 3. Never use var in modern code