CodeOath
← All posts
JavaScript75 min total · 15 parts

JavaScript Core Concepts: Scope, Closures, `this`, and the Event Loop

Contents — Part 3 of 15: var vs. let vs. const: A Direct Comparison
Part 3 of 15 · ~1 min

var vs. let vs. const: A Direct Comparison

These three keywords are often taught together but differ on more than just scope — the full picture is worth having as a single reference:

varletconst
ScopeFunctionBlockBlock
HoistingHoisted, initialized to undefinedHoisted, but in the TDZ until declaredHoisted, but in the TDZ until declared
Re-declaration in the same scopeAllowed (silently overwrites)SyntaxErrorSyntaxError
Re-assignmentAllowedAllowedTypeError — the binding can't be reassigned
Attached to window/global object (browser, top-level script)YesNoNo

const prevents reassigning the variable itself, but it does not make the value immutable — an object or array held in a const binding can still have its contents changed freely:

const arr = [1, 2, 3];
arr.push(4);      // fine — mutating the array's contents, not reassigning `arr`
arr = [5, 6];      // TypeError — this reassigns the binding itself

Object.freeze() (covered in the array/object methods cheat sheet) is the actual tool for preventing mutation of an object's contents — const only locks the variable binding, not the value it points to.

The practical convention in modern JavaScript: default to const everywhere, switch to let only for variables you know will be reassigned (loop counters, accumulators), and avoid var entirely in new code — its function-scoping and silent re-declaration are almost never what you actually want, and let/const catch real bugs at parse time that var would let through silently.