Difficulty: Beginner
What are the differences between var, let, and const in JavaScript? When should you use each?
var, let, and const are the three ways to declare variables in JavaScript, each with different scoping rules and behaviors.
var is function-scoped, can be redeclared and reassigned, and is hoisted with an initial value of undefined. It was the only option before ES6 and is generally avoided in modern code due to its loose scoping.
let is block-scoped, cannot be redeclared in the same scope, can be reassigned, and lives in the Temporal Dead Zone until its declaration. Use let when the variable's value will change.
const is block-scoped like let, but cannot be reassigned after initialization. However, const objects and arrays can still have their contents mutated. Use const by default for all variables whose reference won't change.
function scopeDemo() {
if (true) {
var a = 'var - function scoped';
let b = 'let - block scoped';
const c = 'const - block scoped';
}
console.log(a); // accessible
try { console.log(b); } catch (e) { console.log('b is not defined'); }
try { console.log(c); } catch (e) { console.log('c is not defined'); }
}
scopeDemo();
var leaks out of blocks into the enclosing function. let and const are confined to the block where they are declared.
var x = 1;
var x = 2; // OK - var allows redeclaration
console.log(x);
let y = 1;
// let y = 2; // SyntaxError: already declared
y = 2; // OK - let allows reassignment
console.log(y);
const z = 1;
// z = 2; // TypeError: assignment to constant
console.log(z);
// const with objects - mutation is allowed
const obj = { name: 'Alice' };
obj.name = 'Bob'; // OK - mutating property
console.log(obj.name);
// obj = {}; // TypeError - reassigning reference
var allows both redeclaration and reassignment. let allows only reassignment. const prevents reassignment but not property mutation.
// var in loops - shared reference
const funcsVar = [];
for (var i = 0; i < 3; i++) {
funcsVar.push(() => i);
}
console.log(funcsVar.map(f => f())); // [3, 3, 3]
// let in loops - new binding per iteration
const funcsLet = [];
for (let j = 0; j < 3; j++) {
funcsLet.push(() => j);
}
console.log(funcsLet.map(f => f())); // [0, 1, 2]
var creates one shared variable for all iterations. let creates a fresh binding for each iteration, which closures capture independently.
var, let, const, Block Scope, Function Scope, Redeclaration