Concepts/JavaScript

var vs let vs const

Understand the differences between var, let, and const — scope, hoisting, reassignment, and when to use each.

Side-by-Side Comparison

Featurevarletconst
ScopeFunctionBlockBlock
HoistingYes (undefined)Yes (TDZ)Yes (TDZ)
RedeclarationAllowedNot allowedNot allowed
ReassignmentAllowedAllowedNot allowed
Global object propertyYes (window.x)NoNo

Code Examples

var

  • Function-scoped (not block-scoped)
  • Hoisted and initialized to undefined
  • Can be redeclared in the same scope
  • Can be reassigned
function example() {
  console.log(x) // undefined (hoisted)
  var x = 10
  if (true) {
    var x = 20 // same variable!
  }
  console.log(x) // 20
}

let

  • Block-scoped (respects {curly braces})
  • Hoisted but NOT initialized (TDZ)
  • Cannot be redeclared in the same scope
  • Can be reassigned
function example() {
  // console.log(x) // ReferenceError (TDZ)
  let x = 10
  if (true) {
    let x = 20 // different variable
    console.log(x) // 20
  }
  console.log(x) // 10
}

const

  • Block-scoped (like let)
  • Hoisted but NOT initialized (TDZ)
  • Cannot be redeclared or reassigned
  • Object/array properties CAN still be mutated
const obj = { name: 'Alice' }
obj.name = 'Bob'    // OK — mutating property
// obj = {}          // TypeError — reassignment

const arr = [1, 2, 3]
arr.push(4)          // OK — mutating array
// arr = [5, 6]      // TypeError — reassignment

When to Use Which

const

Default choice. Use for all values that won't be reassigned — objects, arrays, functions, primitives.

let

Use when the binding needs to change — loop counters, accumulators, conditional assignments.

var

Avoid in modern code. Only appears in legacy codebases or when you specifically need function-scoping.

Common Mistakes

Interview Questions

What is the Temporal Dead Zone (TDZ)?

The TDZ is the period between entering a scope and the let/const declaration being reached. Accessing the variable during this period throws a ReferenceError. This exists because let/const are hoisted but not initialized.

Why does var in a for loop cause issues with closures?

Because var is function-scoped, all iterations share the same variable. By the time callbacks execute, the loop has finished and the variable holds the final value. Using let creates a new binding per iteration, fixing this.

Can you change a property of a const object?

Yes. const prevents reassignment of the binding, not mutation of the value. To make an object truly immutable, use Object.freeze() — but note it is shallow.

Deep Dive