JavaScript Interview Prep
JS Engine & Execution

var vs let vs const

The Three Declarations, Fully Decoded

LinkedIn Hook

for (var i = 0; i < 3; i++) setTimeout(() => console.log(i), 100); prints 3, 3, 3. Change var to let and it prints 0, 1, 2.

If you can explain WHY in one sentence, you understand scope. If you can't, this lesson is for you.

var is function-scoped. let and const are block-scoped. var attaches to window. let and const don't. const prevents reassignment of the binding — NOT mutation of the object it points to. All three are hoisted, but only var is auto-initialized to undefined.

In this lesson you'll get the full comparison table, the classic setTimeout trap, the const user.name = ... gotcha, and exactly why var in the global scope can silently overwrite third-party library globals.

If you're still writing var in 2026, you'll stop after reading this.

Read the full lesson -> [link]

#JavaScript #InterviewPrep #VarLetConst #Scope #JSFundamentals #Frontend #CodingInterview


var vs let vs const thumbnail


What You'll Learn

  • Full scope / hoisting / re-assignment / re-declaration comparison
  • Why var leaks out of if and for blocks but let doesn't
  • Why for (var i ...) with setTimeout prints the same number three times
  • What const actually freezes (hint: the binding, not the value)
  • Why global var pollutes the window object

The Full Comparison

This is one of the most asked interview topics. Here's the complete comparison.

Quick Comparison Table

Featurevarletconst
ScopeFunction scopeBlock scopeBlock scope
Hoisted?Yes -> undefinedYes -> TDZYes -> TDZ
Re-declarationAllowedErrorError
Re-assignmentAllowedAllowedError
Global window property?YesNoNo

Scope Difference — The Key Distinction

// var -> function-scoped (ignores blocks like if/for)
function example() {
  if (true) {
    var x = 10;
  }
  console.log(x); // 10 — var leaked out of the if block!
}

// let -> block-scoped (respects all {} blocks)
function example2() {
  if (true) {
    let y = 20;
  }
  console.log(y); // ReferenceError: y is not defined
}

The Classic for Loop Problem

// var: all callbacks share the SAME variable
for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 100);
}
// Output: 3, 3, 3  (NOT 0, 1, 2!)

// let: each iteration gets its OWN copy
for (let i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 100);
}
// Output: 0, 1, 2

Why does var print 3, 3, 3? Because var i is function-scoped — there's only ONE i variable. By the time the setTimeout callbacks run, the loop has finished and i is already 3.

Why does let work? Because let i creates a new i for each loop iteration. Each setTimeout callback captures its own copy.

const with Objects & Arrays

const user = { name: "Rakibul" };

// This works — you're modifying the object, not the binding
user.name = "Hassan";
user.age = 25;

// This fails — you're trying to reassign the binding
user = { name: "Someone else" }; // TypeError: Assignment to constant variable

// Same with arrays
const arr = [1, 2, 3];
arr.push(4);       // Works
arr[0] = 99;       // Works
arr = [5, 6, 7];   // TypeError

const freezes the binding (the reference), not the value. If you want true immutability, use Object.freeze().

var Leaks to window

var globalVar = "I'm on window";
let globalLet = "I'm NOT on window";

console.log(window.globalVar); // "I'm on window"
console.log(window.globalLet); // undefined

This is why var at the global level can accidentally overwrite browser APIs or third-party library globals.

var vs let vs const visual 1


Common Mistakes

  • Treating const as "immutable" — it only prevents re-assignment of the binding; the object it points to can still be mutated. Use Object.freeze() for shallow immutability.
  • Using var inside a loop and expecting each iteration to capture its own value — it won't; all async callbacks share the one function-scoped var.
  • Declaring var at the top of a script and wondering why a library's global got overwritten — var at the top level becomes a property of the window object.

Interview Questions

Q: What's the difference between var, let, and const?

var is function-scoped, hoisted as undefined, can be re-declared and re-assigned, and attaches to window at the top level. let is block-scoped, hoisted into the TDZ, can be re-assigned but not re-declared, and does not attach to window. const is block-scoped, hoisted into the TDZ, and cannot be re-assigned or re-declared — but mutation of the object it references is allowed.

Q: Why does the for loop with var and setTimeout print the same number?

var i is function-scoped — there is only one i for the whole loop. All three callbacks close over the same binding. By the time the setTimeout callbacks fire, the loop has completed and i is 3. let i creates a new per-iteration binding, so each callback captures its own i.

Q: Can you modify a const object's properties?

Yes. const prevents reassignment of the binding (the variable itself), not mutation of the value. Since objects and arrays are reference types, you can modify their properties/elements. Use Object.freeze() for shallow immutability.

Q: What happens if you declare a var variable in the global scope?

It becomes a property of the global object (window in browsers, global in Node). This can accidentally overwrite built-in APIs or third-party globals. let and const declared globally do NOT attach to window, which is safer.

Q: Explain var vs let vs const in one sentence each.

var: function-scoped, hoisted to undefined, attaches to window. let: block-scoped, hoisted into TDZ, re-assignable. const: block-scoped, hoisted into TDZ, binding is locked (but value can still mutate).


Quick Reference — Cheat Sheet

var vs let vs const

                     var           let           const
  Scope              function      block         block
  Hoisting           undefined     TDZ           TDZ
  Re-declare         yes           no            no
  Re-assign          yes           yes           no
  Adds to window     yes           no            no

  Rule of thumb:
    - Reach for const by default
    - let only when you truly need to reassign
    - var: don't, in modern code

Previous: Temporal Dead Zone Next: Memory Heap & Garbage Collection


This is Lesson 1.5 of the JavaScript Interview Prep Course — 14 chapters, 87 lessons.

On this page