DEV Community

Parth
Parth

Posted on

var, let, const — and why JavaScript changed its mind

When I started learning JavaScript, I kept seeing the same advice: use let and const, don't use var.

Usually it came as a rule, not a reason. And a rule you don't understand is a rule you forget — so I went looking for the why.

It turns out var isn't just old-fashioned. It's broken in three specific ways, and let and const exist to fix exactly those three things.

Here they are.

Problem 1: var lets you redeclare the same variable

Watch this:

var name = "Parth";
var name = "Saini";

console.log(name); // "Saini"
Enter fullscreen mode Exit fullscreen mode

No error. No warning. JavaScript just quietly lets you declare the same variable twice.

That sounds harmless in a five-line example. Now imagine a 500-line file where you declare var count at the top, and 300 lines later — having forgotten — you declare var count again. Your original value is gone, and nothing tells you.

let refuses:

let name = "Parth";
let name = "Saini"; // SyntaxError: Identifier 'name' has already been declared
Enter fullscreen mode Exit fullscreen mode

The error is the feature. It catches the mistake at the moment you make it.

Problem 2: var ignores blocks

A block is anything inside curly braces — an if, a for, a bare { }.

You'd expect a variable declared inside a block to stay inside it. var doesn't care:

if (true) {
  var age = 21;
}

console.log(age); // 21 — it escaped!
Enter fullscreen mode Exit fullscreen mode

That variable leaked out of the if and into the surrounding code. var is function-scoped, not block-scoped: it only respects the boundaries of a function, and treats if and for blocks as if the braces weren't there.

let and const are block-scoped. They stay where you put them:

if (true) {
  let city = "Delhi";
  console.log(city); // "Delhi" — fine
}

console.log(city); // ReferenceError: city is not defined
Enter fullscreen mode Exit fullscreen mode

That error is the whole point. The variable did its job inside the block and then stopped existing, which is exactly what you wanted.

Problem 3: var gets quietly moved to the top

This one broke my brain for a while:

console.log(a); // undefined — not an error!
var a = 10;
Enter fullscreen mode Exit fullscreen mode

I used a variable before I declared it, and JavaScript didn't complain. It printed undefined.

The reason is hoisting. Before running your code, JavaScript scans it and moves all var declarations to the top of their scope. So what actually runs is closer to this:

var a;           // moved up, no value yet
console.log(a);  // undefined
a = 10;          // the assignment stays put
Enter fullscreen mode Exit fullscreen mode

The declaration moves. The value doesn't. So you get a variable that exists but is empty — and undefined instead of a helpful error.

let and const are hoisted too, but they refuse to be touched before their declaration line:

console.log(b); // ReferenceError: Cannot access 'b' before initialization
let b = 10;
Enter fullscreen mode Exit fullscreen mode

Again: the error is the improvement. "Cannot access before initialization" tells you exactly what you did wrong. undefined tells you nothing, and lets a broken program keep running.

So what's the difference between let and const?

Simple version:

  • let — the value can be changed later.
  • const — the value cannot be reassigned after you create it.
let score = 10;
score = 20;       // fine

const name = "Parth";
name = "Vatsal";  // TypeError: Assignment to constant variable
Enter fullscreen mode Exit fullscreen mode

But here's the part that trips people up. const locks the variable, not the contents:

const person = { name: "Parth" };

person.name = "Vatsal";  // this works!
console.log(person);     // { name: "Vatsal" }

person = { name: "Aryan" }; // this doesn't — TypeError
Enter fullscreen mode Exit fullscreen mode

You can change what's inside the object. You just can't point the variable at a different object.

Think of const as gluing a label to a box. You can't move the label to another box — but you can still open the box and rearrange what's inside.

The bonus problem: variables you never meant to create

There's a fourth way to make a variable, and it's an accident:

name = "Parth";  // no let, no const, no var
Enter fullscreen mode Exit fullscreen mode

This works. JavaScript silently creates a global variable — one that's visible everywhere in your program. Misspell a variable name during an assignment and you don't get an error; you get a brand new global you didn't ask for, while the one you meant to update sits there unchanged.

This is exactly what "use strict" was made for:

"use strict";

name = "Parth"; // ReferenceError: name is not defined
Enter fullscreen mode Exit fullscreen mode

Do you still need to write it? Usually not — you're probably already in strict mode without knowing it. ES modules (anything with import/export) run in strict mode automatically, and so does most code in React, Next.js, Angular, and modern Node projects.

What I actually took away

I came in expecting "var is old, let is new." That's not the story.

The real story is that var fails silently, and let and const fail loudly. Redeclaring a variable, leaking one out of a block, using one before it exists — var allows all three without a word. let and const throw an error at every one.

That felt backwards to me at first. More errors sounds like a worse language.

But an error at the moment you make a mistake is a gift. The alternative is undefined quietly flowing through your program until it finally breaks somewhere far away — with no clue where it came from.

Use const by default. Use let when the value genuinely needs to change. Reach for var basically never.

And now you know why — not just that.


What tripped you up most when you were learning scope? For me it was hoisting. I'd love to hear about it in the comments.

Top comments (0)