Variables and Program State
How JavaScript names values, why `let` and `const` exist (and `var` mostly doesn't), and what it means for a program to have "state".
A program made only of values would be useless. The interesting thing programs do is remember. A variable is how a program remembers a value and gives it a name.
What a variable really is
A variable is a named slot that holds a value. You can think of it as a labelled box:
When you write:
const age = 28;…you are telling the runtime: create a box, label it age, and
put the value 28 inside it. From now on, anywhere your code
mentions age, the runtime looks in that box and uses what it
finds.
The three keywords: const, let, var
JavaScript has three keywords for declaring variables. In modern code, only two are commonly used:
const— declares a variable whose binding cannot be reassigned.let— declares a variable whose binding can be reassigned.var— the old, original keyword, kept for backwards compatibility. Avoid it in new code.
The rule of thumb is simple and powerful:
Use
constby default. Useletonly when you actually need to reassign. Never usevar.
The reason is that const documents your intent. When a reader
sees const, they know the binding will never change. That makes
the program easier to reason about.
That last block is important. const makes the variable immutable
(you cannot point it at a different value), but it does not
freeze the value inside. If the value is a mutable object (like an
array), you can still change its contents.
Declaration vs initialisation vs assignment
Three words that beginners often mix up:
- Declaration — telling JavaScript a variable exists.
let x; - Initialisation — giving the variable its first value at
declaration.
let x = 5; - Assignment — changing the value of an already-declared
variable.
x = 7;(nolet/constkeyword).
Naming variables
Good variable names are the single biggest factor in code readability. Some rules and conventions:
- Names must start with a letter,
_, or$. They can then contain letters, digits,_, or$. No spaces, no hyphens. - JavaScript is case-sensitive.
userNameandusernameare different names. - The standard style is
camelCasefor variables and functions:userName,totalPrice,currentItem. - Constants that are truly fixed (like configuration values)
are often
SCREAMING_SNAKE_CASE:MAX_RETRIES,PI. - Names should describe the value, not the type. Write
users, notuserArray. Writecount, notcountNumber. - Avoid single letters except as loop counters (
i,j,k) or for very short mathematical formulas.
Both programs do exactly the same work. One reads itself out loud. One requires the reader to guess what each letter means. The first kind of code is debt; the second kind is an asset.
Program state: variables changing over time
The collection of all the variables a program has at any moment, together with the values inside them, is called the state of the program. As the program runs, the state changes: variables get new values, new variables are created, old ones go away.
A useful exercise is to draw a state table as a program runs. Each row is a snapshot after one statement. Each column is a variable.
Take this program:
let x = 5;
let y = 10;
let z = x + y;
x = z;
y = x - 1;| After line | x | y | z |
|---|---|---|---|
| 1 | 5 | — | — |
| 2 | 5 | 10 | — |
| 3 | 5 | 10 | 15 |
| 4 | 15 | 10 | 15 |
| 5 | 15 | 14 | 15 |
This kind of bookkeeping looks tedious, but it is the exact same thing the runtime is doing internally. Practising it on small examples teaches you to "see" state.
Run the program and confirm:
Block scope: where a variable lives
A let or const declared inside { ... } only exists inside
those braces. This is called block scope.
This may look pedantic, but block scoping prevents an entire
category of bugs. A variable used only inside a loop should not
"leak" out of the loop. A temporary value in an if should not
pollute the rest of the function.
We will spend an entire later chapter on scope; this is just a first taste.
Why var is discouraged
var was the original variable keyword. It has two surprising
behaviours that let and const were designed to fix:
varis function-scoped, not block-scoped. Avardeclared inside anifis still visible outside theif.varis "hoisted", meaning the declaration is silently moved to the top of the enclosing function. You can refer to avarbefore it appears in the source, and you'll getundefinedinstead of an error.
These behaviours are surprising, error-prone, and rarely what you
want. New code essentially never uses var. You may see it in old
codebases, and that's fine; you just don't need to write it.
Constants of convenience vs constants of meaning
It is worth distinguishing two reasons to use const:
- Constants of meaning: values that are fundamentally fixed by
the problem.
const PI = 3.14159;const MAX_USERS = 100;Usually givenSCREAMING_SNAKE_CASEnames. - Constants of convenience: ordinary variables that happen not
to be reassigned in this function.
const total = bill + tip;StandardcamelCaseis fine.
The second kind is far more common in modern code. Most local
variables don't need to be reassigned, so they are declared with
const.
A small example tying it together
Let's track a tiny "user session" with three variables, and see how state evolves over the program.
That is a tiny state machine: three variables, evolving over time, in response to events. Almost every interactive program in the world — your email client, your phone's home screen, a video game, this very web page — is, at its core, a much bigger version of this.
Challenge
The harness defines a starting balance of 100 and asks you to perform a series of operations on it.
Write the code so that after running the operations in order, the variables balance, deposits, and withdrawals end up with the expected values:
- Deposit
50(balance up, deposits += 50). - Deposit
30(balance up, deposits += 30). - Withdraw
40(balance down, withdrawals += 40). - Withdraw
10(balance down, withdrawals += 10).
After all four steps:
balanceshould be130depositsshould be80withdrawalsshould be50
Which of the following best describes the recommended way to declare variables in modern JavaScript?
Always use var for backwards compatibility
Use let for everything to keep things flexible
Use const by default; switch to let only when you actually need to reassign; avoid var
Use const for primitives and let for objects