This content originally appeared on DEV Community and was authored by Sylwia Laskowska
If youβre learning JavaScript, one of the first questions youβll face is:
Should I use const or let?
And whatβs up with this old thing called var?
It sounds simple, right?
But trust me β as a senior dev whoβs done countless code reviews and technical interviews, I can tell you:
this is one of those βobviousβ things that many developers still get wrong. 
So letβs break it down β clearly, practically, and once and for all. 
const β constant, but not always frozen
When you use const, youβre saying:
βThis variable name will always refer to the same thing.β
Example:
const name = "Alice";
console.log(name); // Alice
name = "Bob"; // ❌ TypeError
You canβt reassign a const.
But hereβs a fun twist: if itβs an object or array, you can still change its contents 
const numbers = [1, 2, 3];
numbers.push(4); // ✅ works
console.log(numbers); // [1, 2, 3, 4]
numbers = [0]; // ❌ can't reassign
const doesnβt make the value itself immutable β only the reference (the βbox labelβ) is fixed.
If you truly need immutability, use Object.freeze(), but note itβs shallow.
Use const by default.
It keeps your code predictable and self-documenting β if something shouldnβt change, make it const.
let β for things that change
When you do need to reassign a variable, go for let:
let counter = 0;
counter = counter + 1;
console.log(counter); // 1
You can also use let inside blocks (if, for, {}):
if (true) {
let message = "Hello!";
console.log(message); // works here
}
console.log(message); // ❌ ReferenceError
Thatβs because let is block-scoped β it only exists inside the { } where it was declared.
Bonus fact:
Both let and const are hoisted, but they live in the Temporal Dead Zone (TDZ) until the code reaches their declaration.
Thatβs why accessing them too early throws a ReferenceError:
console.log(x); // ❌ ReferenceError
let x = 5;
var β the old-school way (for history lovers)
Before 2015, JavaScript only had var.
It kind of works like let, but with some weird, legacy behaviors.
Example:
if (true) {
var name = "Charlie";
}
console.log(name); // ✅ still works outside the block!
Thatβs because var has function scope, not block scope.
You can even access it before the declaration, due to hoisting:
console.log(a); // undefined
var a = 10;
And hereβs what function scope really means:
function test() {
if (true) {
var greeting = "Hi!";
}
console.log(greeting); // ✅ "Hi!"
}
test();
console.log(greeting); // ❌ ReferenceError
Nowadays, we use let and const instead β but itβs still good to know what var does.
Youβll definitely encounter it in older codebases.
Quick Summary
| Keyword | Can Reassign? | Scope | Hoisted? | Use It? |
|---|---|---|---|---|
const |
No |
Block | (TDZ) |
Default |
let |
Yes |
Block | (TDZ) |
When value changes |
var |
Yes |
Function | (initialized as undefined) |
Avoid (legacy) |
Pro Tip
In modern JavaScript projects (especially with ESLint), youβll often see a rule that says:
βUse const wherever possible.β
Thatβs not dogma β itβs good hygiene.
It keeps your codebase more predictable and helps tools catch bugs early. 
Wrap Up
So, in short:
Use const most of the time
Use let if you really need to change the value
Avoid var unless youβre maintaining ancient code
Keep your variables tidy, your scope clear, and your code modern! 
Your turn:
Do you ever still use var?
Or maybe youβve seen a weird hoisting bug in the wild?
Drop it in the comments β letβs swap battle stories 
This content originally appeared on DEV Community and was authored by Sylwia Laskowska
No