Variables in JavaScript
Bindings control scope and mutability. Prefer const by default, let when reassignment is needed; avoid var.
let vs const vs var
let x = 1 // block-scoped, reassignable
const y = 2 // block-scoped, not reassignable (but object contents can mutate)
var z = 3 // function-scoped, hoisted; avoid in modern code
Hoisting and TDZ
let/const are hoisted but not initialized until their declaration (temporal dead zone). var initializes to undefined at function start.
console.log(a) // ReferenceError (TDZ)
let a = 1
Function declarations are hoisted fully within their scope.
foo() // ok
function foo() {}
Reassignment vs mutation
const prevents rebinding, not mutation of object contents.
const obj = { n: 1 }
obj.n = 2 // ok
// obj = {} // TypeError
Freeze to avoid mutation:
Object.freeze(obj)
Destructuring and defaults
Unpack arrays/objects with defaults and renaming; use rest/spread for copies and merges.
const [first, ...rest] = [1,2,3]
const { name: n = 'anon', age } = { age: 42 }
const copy = { ...obj, age: 43 }
Scope and blocks
Block scope for let/const; function scope for var; globalThis holds globals across environments.
if (true) {
let hidden = 1
}
// hidden is not defined
Globals and strict mode
Avoid accidental globals—assigning to an undeclared identifier creates a global in sloppy mode (not in strict/ESM). Use strict mode/ESM.
Summary
- Default to
const, useletwhen needed, avoidvar - Understand TDZ/hoisting and destructuring; minimize global usage