Q1 of 40 · JavaScript

What is the difference between let, const, and var?

JavaScriptJuniorjavascript-fundamentalsscopinghoistinges6

Short answer

Short answer: var is function-scoped and hoisted (initialised to undefined before its declaration line runs); let and const are block-scoped and throw a ReferenceError if accessed before their declaration (temporal dead zone). Use const by default, let when reassignment is needed, and avoid var in modern code.

Detail

var predates block scoping in JavaScript. Declarations are hoisted to the top of their containing function (or global scope), which means you can reference a var before its line — it just evaluates to undefined until the assignment runs. This makes control-flow bugs hard to spot because the code doesn't fail, it just behaves silently wrong.

let and const are block-scoped (enclosed by the nearest {}). They're still hoisted technically, but they're in the temporal dead zone (TDZ) until execution reaches the declaration — accessing them before that point throws a ReferenceError instead of silently returning undefined. This fail-fast behaviour makes bugs visible immediately.

The difference between let and const is rebinding: const prevents the variable binding from pointing to a different value after initialisation. It does not make objects or arrays immutable — you can still mutate properties or push to an array declared with const. For true immutability, use Object.freeze().

In test automation code: use const for anything you reference but don't rebind (const page = await browser.newPage(), fixture objects, expected values). Use let for loop counters or variables that genuinely need reassignment. var should not appear in modern test code; ESLint's no-var rule enforces this.

// EXAMPLE

scoping.js

// var: function-scoped, hoisted, leaks out of blocks
function badExample() {
  console.log(x); // undefined — not ReferenceError (hoisting)
  var x = 5;
  if (true) {
    var x = 10;   // same binding — overwrites!
  }
  console.log(x); // 10 — leaked out of the if block
}

// const / let: block-scoped, temporal dead zone
function goodExample() {
  // console.log(y); // ReferenceError — TDZ
  const y = 5;
  if (true) {
    let z = 10;   // scoped to this block only
    console.log(z); // 10
  }
  // console.log(z); // ReferenceError — z not in scope
}

// const ≠ immutable object
const steps = [];
steps.push("login"); // fine — the array is mutable
// steps = [];        // TypeError — binding is const

// WHAT INTERVIEWERS LOOK FOR

Scoping rules (function vs block), hoisting and TDZ, and the binding-vs-value mutability distinction for const. Test-specific callout: why var is banned in modern automation code and what ESLint rule enforces it.

// COMMON PITFALL

Saying 'const makes things immutable'. It makes the binding constant, not the value. Demonstrating this with an array or object makes the answer concrete and shows the candidate has actually written JavaScript.