🧠 Mastering let, var, and const in JavaScript β€” Beginner to Advanced Guide with Real Interview Questions

krishankrishan
4 min read
Featurevarletconst
ScopeFunctionBlockBlock
HoistingYes (initialized to undefined)Yes (but not initialized β€” TDZ)Yes (not initialized β€” TDZ)
Re-declarationβœ… Allowed❌ Not allowed❌ Not allowed
Re-assignmentβœ… Allowedβœ… Allowed❌ Not allowed (binding only)
Attached to global objβœ… Yes❌ No❌ No

⚠️ 2. Temporal Dead Zone (TDZ)

Even though let and const are hoisted, they are not initialized. This period between hoisting and declaration is called the Temporal Dead Zone.

console.log(x); // ❌ ReferenceError
let x = 10;

πŸ” 3. Loops and Closures

for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 100);
} // Outputs: 3, 3, 3

for (let i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 100);
} // Outputs: 0, 1, 2

Why? Because let creates a new block scope per iteration, var doesn’t.


πŸ“¦ 4. const and Object Mutability

const obj = { a: 1 };
obj.a = 2; // βœ… Allowed
obj = { b: 2 }; // ❌ Error

const prevents reassignment, not mutation.


βœ… 5. When Should You Use Which?

  • Use const by default for stable references

  • Use let for reassignable values

  • Avoid var unless working with legacy code


πŸ› οΈ 6. Internal Memory Model

Here’s what happens under the hood during the creation phase:

function run() {
  console.log(a); // undefined
  console.log(b); // ReferenceError
  var a = 10;
  let b = 20;
}

Behind the scenes:

  • var a is hoisted and initialized to undefined

  • let b is hoisted but uninitialized β†’ TDZ

  • Accessing b before declaration causes ReferenceError


πŸ’£ 7. Real World Pitfall

var token = "abc123";
if (true) {
  var token = "newToken"; // Overwrites global token
}
console.log(token); // newToken (❌ security risk!)

Fix it with let or const:

let token = "abc123";
if (true) {
  let token = "newToken"; // Scoped inside block
}
console.log(token); // abc123 βœ…

🎯 Interview Questions with Answers

❓ Q1: What is hoisting?

A: JavaScript moves declarations to the top. var is initialized to undefined, let/const stay in the TDZ.


❓ Q2: Why prefer let over var?

A: let is block-scoped and avoids accidental overwrites.


❓ Q3: Is const immutable?

A: No, only the reference is constant. The object/array inside it can be mutated.


❓ Q4: Explain TDZ with an example.

{
  // TDZ for x starts
  console.log(x); // ❌ ReferenceError
  let x = 5;
}

❓ Q5: Difference in loops?

for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 100);
}
for (let i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 100);
}
  • var: prints 3, 3, 3

  • let: prints 0, 1, 2 βœ…


❓ Q6: Can you redeclare let?

let x = 1;
let x = 2; // ❌ SyntaxError

❓ Q7: Is const more performant?

A: Not directly. But helps optimize JS engine assumptions and prevents accidental mutations.


πŸ”š Summary Table

CriteriaUse varUse letUse const
Reassign needed?βœ…βœ…βŒ
Prevent re-declare?βŒβœ…βœ…
Scope neededFunctionBlockBlock
Mutation allowedβœ…βœ…βœ… (objects/arrays)
Default recommendationβŒβœ…βœ… βœ… βœ…

🧠 Final Advice

Use const as your default. Only fall back to let when reassignment is needed. Avoid var unless you’re working on legacy codebases.

10
Subscribe to my newsletter

Read articles from krishan directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

krishan
krishan

πŸ‘‹ Hey, I'm a Frontend Developer passionate about building clean, user-friendly interfaces. πŸš€ Learning and sharing everything from React, JavaScript, HTML/CSS to advanced topics like Data Structures, Algorithms & System Design. πŸ’» Documenting my journey from fundamentals to becoming a top-tier developer β€” one blog at a time. πŸ“š Join me as I break down complex topics into easy, practical lessons β€” with GitHub repos, code snippets, and real-world examples. πŸ” Consistent growth, community learning, and aiming high!