Variables in JavaScript: let, const, and var Explained
A practical guide to declaring variables in modern JavaScript — when to use const, when to use let, why var still exists, and the naming rules that keep your code readable.
What you'll learn
- ✓How to declare variables with const and let
- ✓Why var still exists and when you will see it
- ✓Block scope vs. function scope, in plain terms
- ✓The rules and conventions for naming variables
- ✓What "hoisting" is and why it matters
Prerequisites
- •A working JavaScript setup — see Setup & First Program
A variable is a name you attach to a value so you can refer to it later. Almost every line of useful code involves variables, so it pays to learn the small set of rules well once.
Modern JavaScript has three keywords to declare variables: const, let, and var. You will use const the most, let occasionally, and var essentially never in new code. This post explains why.
Declaring with const
const declares a variable whose binding cannot be reassigned:
const name = "Ada";
const year = 2026;
console.log(`${name} was born in ${year}.`);
Try to reassign and JavaScript throws an error:
const pi = 3.14159;
pi = 3; // TypeError: Assignment to constant variable.
In modern JavaScript style, start with const. Only switch to let when you discover you actually need to reassign the variable. This habit pays off enormously: when you see const, you instantly know the value won’t change, which makes code easier to read.
”Constant” doesn’t mean “immutable”
This trips up nearly every beginner. const prevents reassignment of the variable, not mutation of the value it points to. With objects and arrays, you can still change the contents:
const fruits = ["apple", "banana"];
fruits.push("cherry"); // fine — mutates the array
console.log(fruits); // ['apple', 'banana', 'cherry']
fruits = ["pear"]; // TypeError — reassignment
We will say much more about this when we cover arrays and objects.
Declaring with let
let declares a variable whose value you intend to change:
let score = 0;
score = score + 10;
score += 5; // shorthand for score = score + 5
console.log(score); // 15
Use let for counters, accumulators, and anywhere a loop or conditional changes the value.
let total = 0;
for (let i = 1; i <= 10; i++) {
total += i;
}
console.log(total); // 55
If you’re ever unsure, default to const. JavaScript will tell you immediately if you needed let instead — you’ll get a TypeError the moment you try to reassign.
Declaring with var (and why to avoid it)
var is the original variable keyword from 1995. It still works and you will see it constantly in older code, but it has two quirks that let and const were specifically designed to fix.
Quirk 1: var is function-scoped, not block-scoped
A block is anything between { and } — the body of an if, for, while, or a plain {} you write yourself. let and const are visible only inside the block where they’re declared. var is visible throughout the entire surrounding function, which is almost never what you want:
if (true) {
var a = 1;
let b = 2;
}
console.log(a); // 1 — var leaks out
console.log(b); // ReferenceError: b is not defined
Quirk 2: var is hoisted as undefined
JavaScript “hoists” var declarations to the top of the function and initialises them to undefined, so you can refer to a var before its declaration without an error:
console.log(x); // undefined — surprising
var x = 5;
With let or const, the same pattern throws a clear error:
console.log(y); // ReferenceError: Cannot access 'y' before initialization
let y = 5;
The error is the better behaviour. Bugs from var leaking out of blocks or being silently undefined were a notorious source of confusion before 2015.
When you’ll see var
Almost only in legacy code or short scripts written before ES2015. Recognise it, understand it, do not reach for it.
A side-by-side summary
| Keyword | Scope | Reassign? | Redeclare? | Hoisted as |
|---|---|---|---|---|
const | block | no | no | uninitialised |
let | block | yes | no | uninitialised |
var | function | yes | yes | undefined |
The default-to-const, fall-back-to-let, avoid-var rule covers about 99% of real code.
Try it yourself. In node, paste this and predict the output before pressing Enter:
let count = 5;
{
let count = 10;
console.log(count);
}
console.log(count);Then change both lets to var and run it again. The difference is the entire reason let exists.
Naming variables
JavaScript names must follow a few hard rules:
- They can contain letters, digits,
_and$. - They cannot start with a digit.
- They cannot be a reserved word (
if,for,class, etc.). - They are case-sensitive:
userNameandusernameare different.
Beyond the rules, conventions matter just as much:
- camelCase for variables and functions:
firstName,totalScore,isActive. - PascalCase for classes and constructors:
User,OrderItem. - UPPER_SNAKE_CASE for true constants that never change:
MAX_RETRIES,API_BASE_URL.
Pick names that say what the value means, not what its type is. userCount is better than n. accountBalance is better than x. The few extra characters pay for themselves the first time you read the code again next month.
// Bad
const x = 86400;
// Better
const SECONDS_IN_A_DAY = 86400;
Booleans read better with is/has prefixes
const isLoggedIn = true;
const hasUnreadMessages = false;
const canEdit = user.role === "admin";
When the variable name reads like a yes/no question, the code that uses it reads like English.
Multiple declarations in one line
You can declare several variables in one statement, separated by commas:
let x = 1, y = 2, z = 3;
It is legal but harder to read. One declaration per line is the norm.
Destructuring: unpacking into variables
A modern shorthand for pulling values out of arrays or objects into variables:
const [first, second] = ["Alice", "Bob"];
console.log(first); // Alice
const user = { name: "Ada", age: 30 };
const { name, age } = user;
console.log(name, age); // Ada 30
Destructuring shows up everywhere in modern JavaScript. We will return to it when we cover arrays and objects properly.
Try it yourself. Without running it, predict what this prints:
const a = 10;
let b = 20;
b = b + a;
const c = b * 2;
console.log(a, b, c);Then run it. If you predicted correctly, you are already comfortable with the mental model.
A small worked example
Combining what you’ve learned — a tiny program that calculates a tip and total for a restaurant bill.
const billAmount = 84.50;
const tipPercent = 18;
const tip = billAmount * (tipPercent / 100);
const total = billAmount + tip;
const numberOfPeople = 3;
const perPerson = total / numberOfPeople;
console.log(`Bill: $${billAmount.toFixed(2)}`);
console.log(`Tip (${tipPercent}%): $${tip.toFixed(2)}`);
console.log(`Total: $${total.toFixed(2)}`);
console.log(`Per person: $${perPerson.toFixed(2)}`);
Run it with node tip.js. Every variable is const because no value needs to change. The code reads top-to-bottom like a recipe.
Recap
You now know:
constfor values that don’t get reassigned (the default)letfor values that dovarfor reading older code, not for writing new code- Block scope is the modern norm;
var’s function scope is a relic - Variable names follow simple rules and clear conventions (camelCase for variables, UPPER_SNAKE_CASE for true constants)
- Destructuring is a clean way to unpack arrays and objects into variables
Next steps
Variables hold values. Next, we look at the full set of value kinds JavaScript supports — strings, numbers, booleans, null, undefined, objects — and how to check what you’ve got.
→ Next: JavaScript Data Types: The Complete Beginner Guide
Questions or feedback? Email codeloomdevv@gmail.com.