, ,

var vs. let vs. const: Use Cases that Matter

Posted by

Stop guessing and start coding with clarity — here’s when to use each variable declaration in modern JavaScript.

Stop guessing and start coding with clarity — here’s when to use each variable declaration in modern JavaScript.

Introduction

You’ve probably seen this question asked in every JavaScript interview and tutorial:

👉 What’s the difference between var, let, and const?

At first glance, it seems simple:

  • var is old.
  • let is new.
  • const means constant.

But when you actually start coding, things get messy:

  • Why does var behave differently inside loops?
  • Why does const allow object mutation?
  • Why does let throw errors while var doesn’t?

The truth is, each keyword has distinct behavior, scope rules, and use cases. Misusing them can lead to subtle bugs — the kind that take hours to debug.

In this post, we’ll break it down step by step, with real-world examples, pitfalls, and best practices so you’ll know exactly which one to use and when.


1. Why Three Keywords Exist

JavaScript didn’t always have three.

  • Before ES6 (2015): Only var existed. It worked, but had quirks.
  • After ES6: let and const were introduced to fix scoping issues and make code more predictable.

👉 Rule of thumb today: In modern code, you almost never need var. But knowing it is essential because:

  1. Legacy codebases still use it.
  2. It explains many JavaScript quirks (like hoisting).

2. Scoping Rules: The Big Divide

var → Function Scope

function testVar() {
if (true) {
var message = "Hello, var!";
}
console.log(message); // ✅ Works
}
testVar();

Even though message is inside an if block, it “escapes” — because var is function-scoped, not block-scoped.


let & const → Block Scope

function testLetConst() {
if (true) {
let msg1 = "Hello, let!";
const msg2 = "Hello, const!";
}
console.log(msg1); // ❌ ReferenceError
console.log(msg2); // ❌ ReferenceError
}
testLetConst();

Both are block-scoped → safer, more predictable.

👉 Real-world effect:
 When looping over arrays, using var can cause unexpected leaks. Using let/const keeps variables tightly scoped.


3. Hoisting: The Gotcha

Hoisting means “moving declarations to the top of scope” during compilation. But not all declarations are equal.

console.log(a); // undefined
var a = 10;

console.log(b); // ❌ ReferenceError (TDZ)
let b = 20;

console.log(c); // ❌ ReferenceError (TDZ)
const c = 30;
  • var → Hoisted & initialized with undefined.
  • let / const → Hoisted but uninitialized → fall into the Temporal Dead Zone (TDZ) until declaration.

👉 Pro tip: Always declare variables at the top of their scope to avoid confusion.


4. Reassignment & Redeclaration

var

  • Can be reassigned.
  • Can be redeclared in the same scope.
var x = 1;
var x = 2; // ✅ Allowed
x = 3; // ✅ Allowed

let

  • Can be reassigned.
  • Cannot be redeclared in the same scope.
let y = 1;
y = 2; // ✅ Allowed
let y = 3; // ❌ SyntaxError

const

  • Cannot be reassigned.
  • Cannot be redeclared.
  • ⚠️ But objects/arrays declared with const are mutable.
const z = 1;
z = 2; // ❌ TypeError

const obj = { name: "Alice" };
obj.name = "Bob"; // ✅ Allowed (reference unchanged)

👉 Gotcha: const locks the binding, not the contents.


5. Real-World Example: Loops

With var

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

All callbacks share the same i, which ends at 3.


With let

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

let creates a new binding per iteration → closures work correctly.

👉 Impact: This fixes one of the most common bugs in async loops.


6. When to Use var

Use var only when:

  • Maintaining legacy code.
  • You explicitly need function-scoped variables.
  • You’re targeting environments without ES6 support.

Otherwise → avoid it.


7. When to Use let

Use let when:

  • The variable will be reassigned.
  • Example: Loop counters, mutable state.
let total = 0;
for (let i = 1; i <= 5; i++) {
total += i;
}
console.log(total); // 15

8. When to Use const

Use const as your default.

  • Most variables don’t need reassignment.
  • Signals intent: “this won’t change.”
  • Safer in large codebases.
const API_URL = "https://api.example.com";
const user = { id: 1, name: "Rahmat" };

👉 Functional programming patterns especially love const.


9. Best Practices

  • Prefer const. Downgrade to let if reassignment needed.
  • Avoid var. Consider it legacy.
  • Use ESLint/Prettier rules to enforce:
"rules": {
"no-var": "error",
"prefer-const": "error"
}
  • Think intent, not habit. Always ask: Should this ever change?

10. Quick Decision Tree

  • Need reassignment? → use let.
  • Never reassigned? → use const.
  • Old-school or function-scope needed? → use var.

That’s it.


11. Real Project Case Study

I once reviewed a Node.js service where a developer used var for loop counters inside async database calls. Guess what happened?

  • Instead of updating 3 different records, all callbacks referenced the same final value of var i.
  • Fix was as simple as changing varlet.
  • Saved hours of debugging.

👉 Sometimes, the difference is more than academic — it’s production bugs.


Conclusion

We covered a lot, but the essence is simple:

  • var → function-scoped, legacy, avoid unless necessary.
  • let → block-scoped, reassignable.
  • const → block-scoped, not reassignable (but contents can mutate).

👉 Pro Tip: Start with const. If you realize reassignment is required, switch to let. Forget var unless you’re in a museum project.


Call to Action

What’s your team’s convention for var vs let vs const?

💬 Share your thoughts in the comments.
🔖 Bookmark this for future interviews and code reviews.
👩‍💻 Share with that teammate who still writes var in 2025.

Leave a Reply

Your email address will not be published. Required fields are marked *