Skip to content
C Codeloom
JavaScript

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.

·7 min read · By Yash Kesharwani
Beginner 9 min read

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 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

KeywordScopeReassign?Redeclare?Hoisted as
constblocknonouninitialised
letblockyesnouninitialised
varfunctionyesyesundefined

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:

  1. They can contain letters, digits, _ and $.
  2. They cannot start with a digit.
  3. They cannot be a reserved word (if, for, class, etc.).
  4. They are case-sensitive: userName and username are 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:

  • const for values that don’t get reassigned (the default)
  • let for values that do
  • var for 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.