Programs, values, and types · Lesson 6 of 77 · concept
Naming values: let and const
About 45 minutes.
By the end of this lesson you can
- Declare a value with const and explain why that is the default choice.
- Use let for a value that genuinely has to change, and reassign it.
- Say what happens when a const is reassigned, and why the program stops.
- Choose names a stranger could read, following the conventions this language uses.
A name is a label you tie to a value
Explanation
So far every value has been used the instant it was made. That does not scale past two lines. A DECLARATION makes a value and ties a name to it, so the rest of the program can refer to it without repeating how it was worked out.
The shape is always the same: the keyword, the name, an equals sign, and an expression. Read the equals sign as the word becomes, never as the word equals — it is an instruction to attach, not a claim that two things are the same. That reading also stops you from writing a single = where you meant a comparison.
Naming is not decoration. The moment a value has a name, the intent of the line above it is recorded permanently, in the one place nobody can forget to update: the code itself.
const by default, let when it truly has to change
Explanation
const declares a name that cannot be pointed at a different value afterwards. It must be given a value at the moment you declare it — a const with nothing after the equals sign is not allowed, because there would be no later opportunity to supply one.
let declares a name you can point at a new value later, by writing the name, an equals sign and the new expression. No keyword the second time: the keyword is what creates the name, and it happens once.
The working rule, and it is close to universal in modern JavaScript: start with const every time, and change it to let only when you write a line that has to reassign it. This is not fussiness. A const tells every future reader, in one word and at a glance, that this value is fixed for the rest of its life — so when they are hunting for what changed a value, they can skip it entirely.
There is an older keyword, var, in a great deal of existing code. It behaves differently in ways that caused enough bugs for the language to add two replacements, and the honest summary is: read it when you meet it, do not write it. The module on functions explains what it actually does, once scope exists to explain it with.
const freezes the label, not the value
A mental model
Picture a name as a luggage tag tied to a suitcase. const means the tag cannot be untied and moved to a different suitcase. It says nothing at all about what is inside this one.
For the values in this module — numbers, text, booleans — the distinction never shows up, because none of them can be altered from the inside anyway. It matters enormously for the collections in module 4: a const array can have items added to it all day, because the tag is still on the same array. If that sounds like a contradiction now, park it. The wording to keep is the one that stays true either way: const stops reassignment, not change.
What you may call things, and what you should
Explanation
The rules are few. A name may contain letters, digits, underscores and dollar signs; it may not start with a digit; it is case-sensitive; and it may not be one of the language's own keywords, so const const is out.
The conventions matter more than the rules, because they are what makes code readable across a whole industry. JavaScript names run words together with a capital at the start of each after the first: unitPrice, totalCents, isOutOfStock. That style is called camelCase. Nothing enforces it, and everyone follows it.
Beyond that, the rule of thumb: a name should say what the value IS, not how it was computed or what type it is. total beats t and beats totalNumber. Booleans read best as a claim — isReady, hasStock. Names are free, and a longer one that removes a question is always the better deal.
Three ways a declaration goes wrong
A common mistake
Reassigning a const. The specification says this raises a TypeError, and the program stops on that line — some engines notice even earlier, while reading the file, and refuse to start it at all. Either way you get told immediately, which is the whole benefit: the alternative is a value quietly changing under you at three in the morning.
Declaring the same name twice in the same scope. Writing let total twice, or const after let, is a SyntaxError — an error found while the code is being read, before a single line runs. If you meant to change the value, drop the second keyword and just assign.
Using a name on a line above its declaration. Names declared with let and const are not usable before the line that declares them; touching one early stops the program with a ReferenceError rather than quietly giving you nothing. Declare a value just above where you first need it, and the problem never arises.
Why this is the lesson experienced developers would flag
Why it matters
Ask a room of professionals what makes code good and naming will come up before anything technical. The reason is arithmetic: a line of code is written once and read dozens of times, and every read is faster when the names say what they mean.
There is a debugging payoff too. When something is wrong with a value, the first question is always where did this change? const answers that question for every name it guards, permanently and without you having to look. A file where only three names are let is a file with only three places worth searching.
Recap
Recap
A declaration ties a name to a value: read = as becomes. Use const by default; it must be initialised and cannot be reassigned, though it does not freeze what is inside a collection. Use let only where a reassignment actually happens, and write the keyword only once. Names are camelCase and should say what the value is.
Worked examples
Every output below was produced by actually running the code in the same sandbox your exercises run in — it is not a prediction.
One fixed value, one that moves
A price that never changes and a quantity that does. Watch the total change only because it is recalculated after the reassignment — order of statements is doing real work here.
1const pricePerNight = 120;2let nights = 2;3console.log(pricePerNight * nights);4 5nights = 5;6console.log(pricePerNight * nights);- line 1
Fixed for the life of the program, and marked as such for every reader.
- line 2
let, because line 5 is going to change it. Without that line, this would be a const.
- line 5
No keyword. let created the name once; this only points it at a new value.
- line 6
Recalculated here. The earlier printed 240 did not change retroactively — it was worked out from the value as it stood at that moment.
What it prints
240600
What reassigning a const looks like
Written deliberately to fail. The point is that the failure is immediate and loud, at the exact line responsible, rather than a wrong number surfacing somewhere else later.
1const total = 10;2total = 20;3console.log(total);- line 2
The offending line. The program stops here.
- line 3
Never runs, so nothing is printed at all — not even the original 10.
This one does not run hereIt is written to fail. Reassigning a const raises an error that stops the program before line 3, so there is no output to publish. Paste it into the run pad if you want to read the message your engine gives.
The same arithmetic, twice
Both halves compute the same number. Only one of them tells you what the number is for, and neither costs the machine anything different.
1const q = 3;2const p = 4.5;3console.log(q * p);4 5const quantity = 3;6const unitPrice = 4.5;7const orderTotal = quantity * unitPrice;8console.log(orderTotal);- line 3
Correct, and meaningless out of context. Is that a price, a weight, a duration?
- line 7
Naming the result as well as the inputs means the next line can say orderTotal and be understood without reading upwards.
What it prints
13.513.5
Check yourself
Not scored, not stored. Getting one wrong is the useful part.
One name, reassigned twice, printed once. What is the final value?
let count = 1;count = count + 1;count = count * 10;console.log(count);
A program works out a VAT rate of 0.2 at the top and never changes it. Which declaration is right?
What happens when a program tries to reassign a const?
Write it yourself
Exercise · core · 4 tests
The customer changes their mind
A single item costs 4.5 and that price is fixed. The customer starts by wanting 2 of them and then changes their mind and wants 5. Declare quantity with let, starting at 2, then reassign it to 5. After that, declare total as unitPrice multiplied by quantity. Do not change the line that declares unitPrice.
quantity ends at 5, unitPrice is still 4.5, and total is 22.5. total must be worked out after the reassignment, because a value computed earlier does not update itself when its ingredients change later.
Define quantity and total at the top level of your code — the tests call them by name.
Worth remembering
- Why prefer const over let by default?
It cannot be reassigned, so every reader knows at a glance that the value is fixed — and when a value is wrong, only the let names need investigating.
- Does const make a value unchangeable?
No. It stops the name being pointed at a different value. The contents of a collection held by a const can still be changed.
Check this lesson against the source
We wrote the explanation; we did not invent the facts. This is the page that backs them.
Check there: That a const declaration requires an initialiser, that reassignment throws a TypeError, and that the contents of a constant object may still be changed.
Check there: That let declarations are block-scoped and cannot be accessed before the declaration is evaluated.
Check there: That var is function-scoped rather than block-scoped, unlike let and const.
Prefer to read the source in a structured breakdown? Turn this doc into a breakdown