Decisions and loops
Asking questions with if, repeating work with for, and walking a list with the for…of shape.
if, and the strictness of ===
An if runs the block under it when the question is true; else catches the rest. The braces mark the block, so the layout is free — but indenting the inside is what makes it readable.
JavaScript has two equality operators, and the difference matters. === asks whether two values are the same type and value; == will convert before comparing, so "3" == 3 is true and "3" === 3 is not. Use === — it asks the question you meant.
The extra equals sign is not decoration. == has a table of conversions, and the table has cases that surprise even experienced programmers: null == undefined is true, and 0 == "" is true. === has no table, so the answer depends only on the two values in front of you.
A question, and a walk through a list
const temperature = 12;
if (temperature > 18) {
console.log("Light jacket.");
} else {
console.log("Warm coat.");
}
const loaves = ["white", "rye", "focaccia"];
for (const loaf of loaves) {
console.log(loaf);
}for…of, for arrays
for (const loaf of loaves) hands the body one item per turn, in order — the same shape as for item in list in Python. The name inside is just a name for the current item; it is not an index and it has nothing to do with the array’s positions.
The older for (let i = 0; i < loaves.length; i++) still exists, and is what you reach for when the position genuinely matters. When it does not, the for…of form says what is happening with less to read.
Combining questions
&& means both, || means either, and ! flips a boolean. They read as words if you say them that way: "if there is flour and there is time, bake".
Keep one question per if where you can. A condition with three &&s is usually two decisions wearing a coat, and the second one deserves its own block.
What counts as true
An if does not demand a boolean. It accepts any value and asks whether it is truthy. Six values are falsy: false, 0, "", null, undefined and NaN. Everything else is truthy — including "0", "false" and an empty array.
That shortcut is convenient and occasionally wrong. if (input.value) looks like "if something was typed", and it is — but a field containing a space is truthy, and a field containing the text "0" is truthy too. When zero is a legal answer, test the value explicitly instead of relying on truthiness.
Falsy is a short list, and it is worth memorising because the exceptions are where bugs live: 0, "", null, undefined, NaN and false. Everything else is truthy, including an empty array and an empty object, which is why if (list) does not test whether the list has items.
The three parts of a counting loop
A counting loop has a start, a test and a step: for (let i = 0; i < 5; i++). The test runs before every turn, including the first, so i < 5 gives five turns numbered 0 to 4. Writing i <= 5 gives six, which is the off-by-one mistake in its natural habitat.
The step is what guarantees the loop can end. Remove i++ and the test stays true forever; the page freezes and the browser eventually offers to stop the script. If a loop misbehaves, log the counter on the first few turns — the answer is usually visible immediately.
A worked loop, traced
Take for (let i = 0; i < 5; i++). Before the first turn i is 0, the test passes, and the body runs with 0. The step adds one, and the same three steps repeat. When i reaches 5 the test fails, the body is skipped, and the loop is over. The values seen inside are 0, 1, 2, 3 and 4 — five turns, none of them 5.
Change the test to i <= 5 and the body also runs with 5, which is six turns. Change the step to i += 2 and the values are 0, 2, 4, then 6, which fails the test; three turns. Read the start, the test and the step together, and the count follows.
Three mistakes to recognise: if (x = 5) assigns and is always true, so use === for the comparison; a counting loop with no step never ends; and an empty string is falsy while the string "0" is truthy, so a condition built on a field value needs to say what it actually means.
Try these next
- Count down from 5 to 1 with a loop, then log "liftoff" after it.
- Log only the even numbers from 1 to 10, using
continueto skip the odd ones. - Rewrite a counting loop as
for…ofover an array, and notice which name disappears.
Odd or even
Walk the numbers from 1 to 6 with a loop, and log each one with "odd" or "even" after it.
3 left to do
- The numbers are walked with a loop
- There is a decision in the loop
- Each result is logged
for (let n = 1; n <= 6; n++) counts; n % 2 === 0 is the even test (the remainder of dividing by two).
A loop that adds up
Add the whole numbers from 1 to 10 with a loop, keep the running total in a variable, and log the answer. Then log the even numbers from 1 to 10 on their own.
3 left to do
- The numbers are walked with a loop
- A running total is kept
- The answer is logged
Start let total = 0;, then total += n; inside the loop. For the evens, if (n % 2 === 0) decides whether to log.
A loop that logs nothing usually means the list is empty or the condition is never true. Log the list itself once — nine times out of ten that is the whole bug.
Check what you learned
One question at a time. A wrong answer explains itself — take another go.
Part 1 of 5
Why prefer === over ==?
