Module 4 ¡ if, switch and Loops
Decisions and Loops: The Picture
In this lesson
- Write an
ifwith anelsethat picks one of two lines, reading the condition as truthy or falsy. - Name the three parts of a
forloop and say in which order they run. - Walk through every value of a list with
for...of, and explain why a loop stops.
Zara's step counter keeps one number a day, and her goal is 8000 steps. She wants a line for each day of the week: met or short. Her first program checks day 1, then she copies the check for day 2, then for day 3. A week is seven copies, a month is thirty, and the copy for day 23 still says day 22. This lesson replaces every copy with one decision and one loop.
Zara's copied checks
Here is Zara's first program, for three days. Each check is the same five lines with a different day in it.
const day1 = 7500;
const day2 = 8000;
const day3 = 12030;
const goal = 8000;
if (day1 >= goal) {
console.log("day 1: met");
} else {
console.log("day 1: short");
}
if (day2 >= goal) {
console.log("day 2: met");
} else {
console.log("day 2: short");
}
if (day3 >= goal) {
console.log("day 3: met");
} else {
console.log("day 3: short");
}
day 1: short
day 2: met
day 3: met
It works, and it does not grow. Two ideas fix it. A decision runs some lines only when a condition holds: that is if. A loop runs the same lines again and again, once per day: that is for. Together they handle any number of days.
const input = require("fs").readFileSync(0, "utf8");
const tokens = input.split(/\s+/).filter(Boolean);
let at = 0;
const next = () => tokens[at++];
const nextInt = () => Number(next());
const out = [];
const GOAL = 8000;
const n = nextInt();
for (let day = 1; day <= n; day++) {
const steps = nextInt();
if (steps >= GOAL) {
out.push("day " + day + ": met");
} else {
out.push("day " + day + ": short");
}
}
console.log(out.join("\n"));
day 1: short
day 2: met
day 3: met
day 4: short
day 5: met
day 6: short
day 7: met
That output is for the input 7, then 7500 8000 12030 0 9100 4200 15000. The check is written once. The loop runs it seven times, and it would run it 365 times for a year without one extra line. So a loop repeats lines, and an if inside it decides what each repeat does.
if: lines that run only when a condition holds
An if statement has a condition in round brackets and a block in curly braces. A block is a group of lines that belong together. When the condition holds, the block runs. When it does not, the program skips the block and carries on after it.
const steps = 9100;
if (steps >= 8000) {
console.log("Goal met. Well walked.");
}
console.log("Done for today.");
Goal met. Well walked.
Done for today.
Change steps to 500 and only the last line prints. An else block after the if runs in exactly the other case, so one of the two blocks always runs, never both.
The condition does not have to be a comparison. JavaScript reads any value as truthy or falsy, the rule from Module 2. The falsy values are false, 0 (with -0 and 0n), "", null, undefined and NaN, and everything else is truthy.
const name = "";
if (name) {
console.log("Hello, " + name);
} else {
console.log("Hello, stranger");
}
const unread = 3;
if (unread) {
console.log(unread + " new messages");
}
Hello, stranger
3 new messages
The empty string is falsy, so the else block ran. The number 3 is truthy, so its block ran. So if (value) asks one question: is this value truthy? A comparison such as steps >= 8000 is just a value that is always true or false.
This track always writes the braces, even around one line. Common mistakes 2, near the end, shows what happens without them.
for: three parts, and the order they run in
The round brackets of a for loop hold three parts, separated by semicolons.
- The start,
let i = 1, runs once, before anything else. - The test,
i <= 3, runs before every pass. When it is truthy, the body runs. When it is falsy, the loop ends. - The step,
i++, runs after every pass of the body. It adds 1 toi.
The body is the block in braces, and one run of it is a pass. Watch the order. Step through the loop below and keep an eye on the test column: it is checked before each pass.
Here is the same loop as a program. Each pass prints the value of i it saw.
let total = 0;
for (let i = 1; i <= 3; i++) {
console.log("pass with i = " + i);
total += i;
}
console.log("total " + total);
pass with i = 1
pass with i = 2
pass with i = 3
total 6
The test ran four times: three times it said yes, and the fourth time, with i at 4, it said no. The two pictures below put the if and the for side by side. The for is an if with an arrow back to the top.
So in a for loop, the start runs once, the test runs before every pass, and the step runs after every pass. The loop ends the first time the test is falsy.
Where the loop's i lives
A name declared with let in the start of a for belongs to the loop. It exists inside the round brackets and the body, and nowhere else. So two loops can each have their own i, and neither one sees the other's.
for (let i = 0; i < 2; i++) {
console.log("first loop", i);
}
for (let i = 5; i < 7; i++) {
console.log("second loop", i);
}
first loop 0
first loop 1
second loop 5
second loop 6
After the loop, i is gone, and reading it is an error (Common mistakes 4). Keep any value you need later in a variable declared before the loop, the way total was. So declare a loop's counter in its start, and a result before the loop.
for...of: one pass per value
Often the job is not "count to n" but "look at every value in this list". JavaScript keeps a list of values in an array, written in square brackets: [4200, 9900, 8000]. Module 7 teaches arrays properly. Here you only need two facts: an array holds values in order, and week.length is how many it holds.
A for...of loop hands you the values one at a time. There is no counter to start, test or step: the loop takes the next value on each pass and stops after the last one.
const week = [4200, 9900, 8000, 7999, 15000];
let count = 0;
for (const steps of week) {
if (steps >= 8000) {
count++;
}
}
console.log(count + " of " + week.length + " days met the goal");
3 of 5 days met the goal
steps is a const, and that is allowed: each pass gets a fresh steps with the next value, so nothing is ever reassigned. A string works the same way, one character per pass. Module 3 shows where "one character" gets subtle.
for (const letter of "Zara") {
console.log(letter);
}
Z
a
r
a
So for...of is the loop for "every value of this list", and a for with a counter is the loop for "count from here to there". Lesson 04 turns that into a flowchart.
Why a loop stops, and when it never does
A loop stops because its test finally answers falsy. In a for loop the step moves i toward that answer on every pass. If the test is falsy from the very first check, the body runs zero times, and that is not an error.
const n = 0;
for (let i = 1; i <= n; i++) {
console.log("never printed");
}
console.log("the loop ran 0 times");
the loop ran 0 times
If nothing moves the test toward false, the loop never stops. That is an infinite loop. The while loop below, from lesson 02, forgot to add 1 to i, so i < 5 stays true for ever.
let i = 0;
let total = 0;
while (i < 5) {
total += i;
}
console.log(total);
Nothing prints. On the Playground, signed out, this program ran for about 10 seconds and then stopped with the verdict Time Limit Exceeded (a run on 2026-10-07). The judge does the same to a submitted program. So every loop needs something inside it that moves its test toward false.
if, else and the two for loops
if (condition) {
// runs when condition is truthy
} else {
// runs when condition is falsy (the else part is optional)
}
for (start; test; step) {
// the body: runs while test is truthy
}
for (const value of list) {
// one pass per value of the list, in order
}
conditionandtestare any expression, read as truthy or falsy.startruns once;testruns before every pass;stepruns after every pass.listis an array or a string;valuetakes the next item on each pass.- The braces mark the block. This track always writes them.
The smallest decision: one number, one condition, two possible lines.
const celsius = 31;
if (celsius >= 30) {
console.log("hot: carry water");
} else {
console.log("not hot");
}
hot: carry water
31 is at least 30, so the if block runs and the else block is skipped. Set celsius to 30 and the same line prints, because >= includes the edge.
Bob puts 10 taka in a jar on day 1, 20 on day 2, 30 on day 3, and so on for a week. A for loop counts the days and keeps the running total.
let saved = 0;
for (let day = 1; day <= 7; day++) {
saved += day * 10;
console.log("day " + day + ": " + saved);
}
day 1: 10
day 2: 30
day 3: 60
day 4: 100
day 5: 150
day 6: 210
day 7: 280
saved is declared before the loop, so it keeps growing across passes. Declared inside the body, it would start again at 0 on every pass.
The program Zara actually keeps. It reads n, then n daily step counts. It reports the week's total and how many rest days she took, a rest day being under 1000 steps.
const input = require("fs").readFileSync(0, "utf8");
const tokens = input.split(/\s+/).filter(Boolean);
let at = 0;
const next = () => tokens[at++];
const nextInt = () => Number(next());
const out = [];
const n = nextInt();
let total = 0;
let restDays = 0;
for (let day = 1; day <= n; day++) {
const steps = nextInt();
total += steps;
if (steps < 1000) {
restDays++;
}
}
out.push("total " + total);
out.push("rest days " + restDays);
console.log(out.join("\n"));
total 52230
rest days 2
That output is for the input 7, then 7500 8000 12030 0 9100 600 15000. The loop reads one count per pass with nextInt(), so it reads exactly n of them. The if decides which passes add to restDays.
Where this is used
- The language standard itself.
Array.prototype.includesasks whether an array holds a value. ECMA-262 defines it as a loop, "Repeat, while k < len", with anifinside that returns true on a match. - Express, the Node web framework. Express 4's router keeps an app's middleware in a list. It walks the list with a
whileloop and tests each layer against the request's path before running it. - Node's event loop. libuv, the C library under Node, runs it as a
whileloop in itsuv_runfunction. Each turn handles a batch of events, until nothing is left to wait for (Module 12). - Browser games. A game draws a frame, then asks
requestAnimationFrameto call it again before the next screen refresh, usually about 60 times a second. Each frame is one pass of a loop, with aniffor every key the player holds (Module 14).
Common mistakes
1. A semicolon after the condition.
const steps = 500;
if (steps >= 8000); {
console.log("Goal met");
}
Goal met
No error, and the wrong answer: 500 steps "met" the goal. The semicolon ends the if with an empty statement, and the braces after it are a separate block that always runs. Delete the semicolon. You will type it because almost every other line ends in one.
2. Two lines under an if without braces.
const steps = 500;
if (steps >= 8000)
console.log("Goal met");
console.log("Badge unlocked");
Badge unlocked
Without braces, an if owns only the one statement after it. The indentation suggests the badge line belongs to the if, but JavaScript ignores indentation. Write the braces every time. You will leave them out because the first version had one line, and the second line arrives a week later.
3. const as the counter of a for loop.
for (const i = 0; i < 3; i++) {
console.log(i);
}
0
TypeError: Assignment to constant variable.
The first pass runs, then the step i++ tries to change a constant, and Node 22 stops the program. A counter changes, so it is a let. You will write const because for...of uses it, and there each pass gets a new name instead of changing the old one.
4. Reading the counter after the loop.
for (let i = 0; i < 3; i++) {
console.log(i);
}
console.log("finished at " + i);
0
1
2
ReferenceError: i is not defined
The loop's i ended with the loop. If you need a value afterwards, declare a variable before the loop and set it inside. You will try it because the last value of i feels as if it should still be lying around.
David's rocket game starts with a countdown. Print the numbers from n down to 1, then the word that launches the rocket.
Input. One whole number n.
Output. n lines with n, n - 1, and so on down to 1, then one line Go!.
Constraints. 1 <= n <= 1000.
Sample. Input 3 gives 3, 2, 1 and Go! on four lines.
const input = require("fs").readFileSync(0, "utf8");
const tokens = input.split(/\s+/).filter(Boolean);
let at = 0;
const next = () => tokens[at++];
const nextInt = () => Number(next());
const out = [];
// your code: read with next() and nextInt(), push every line of output to out
console.log(out.join("\n"));
Not graded on its own. A for loop can count down: start at n, test i >= 1, and step with i--.
Zara's step counter, done properly. For each day, say whether she met her goal, then say how many days she met it.
Input. The first line holds n and the goal g. The second line holds n whole numbers, the steps of each day.
Output. n + 1 lines: for each day in order, met when its steps are at least g, otherwise short; then the number of days met.
Constraints. 1 <= n <= 100000. 0 <= g <= 100000. 0 <= steps <= 100000.
Sample. Input 5 8000 and 7500 8000 12030 0 9100 gives short, met, met, short, met and 3 on six lines.
const input = require("fs").readFileSync(0, "utf8");
const tokens = input.split(/\s+/).filter(Boolean);
let at = 0;
const next = () => tokens[at++];
const nextInt = () => Number(next());
const out = [];
// your code: read with next() and nextInt(), push every line of output to out
console.log(out.join("\n"));
Graded as steps-goal. The hidden tests include a day that hits the goal exactly, a goal of 0 and a single day, so read "at least" carefully.
Zara wants to know how often she beat the day before. Count the days whose steps are higher than the previous day's. Day 1 has no previous day, so it never counts.
Input. n, then n whole numbers, the steps of each day.
Output. One number: how many days had more steps than the day before.
Constraints. 1 <= n <= 100000. 0 <= steps <= 100000.
Sample. Input 5 and 4200 9900 8000 8100 15000 gives 3: 9900 beat 4200, 8100 beat 8000, and 15000 beat 8100.
const input = require("fs").readFileSync(0, "utf8");
const tokens = input.split(/\s+/).filter(Boolean);
let at = 0;
const next = () => tokens[at++];
const nextInt = () => Number(next());
const out = [];
// your code: read with next() and nextInt(), push every line of output to out
console.log(out.join("\n"));
Not graded on its own. Keep yesterday's value in a let declared before the loop, and update it at the end of every pass. Then try n = 1 and two equal days.
Zara's app gives a badge for the longest streak: the most days in a row that met the goal. Find the length of her longest streak.
Input. The first line holds n and the goal g. The second line holds n whole numbers, the steps of each day.
Output. One number: the length of the longest run of consecutive days with steps of at least g, or 0 when no day met it.
Constraints. 1 <= n <= 100000. 0 <= g <= 100000. 0 <= steps <= 100000.
Sample. Input 7 8000 and 9000 8000 100 8500 9100 12000 50 gives 3: days 4, 5 and 6.
const input = require("fs").readFileSync(0, "utf8");
const tokens = input.split(/\s+/).filter(Boolean);
let at = 0;
const next = () => tokens[at++];
const nextInt = () => Number(next());
const out = [];
// your code: read with next() and nextInt(), push every line of output to out
console.log(out.join("\n"));
Not graded on its own. You need two counters: the streak running now, and the best one so far. Decide what each does on a day that misses the goal, and test a week where the best streak is the last one.
Run in CompilerCommon doubts
Do I really need braces when the block has one line?
The language lets you leave them out for a single statement. This track always writes them. So does the Google JavaScript Style Guide, which asks for braces on every control structure, and ESLint's
curlyrule can enforce it. Common mistakes 2 is the reason: the second line always arrives later.Why do some loops start at 0 and others at 1?
Both run n passes when the test matches the start.
for (let i = 0; i < n; i++)counts 0 to n - 1, which matches the positions in an array (Module 7).for (let day = 1; day <= n; day++)counts 1 to n, which matches how people number days. Pick the one whose numbers you print.Is
i++different fromi += 1as the step?Not as the step. The step's own value is thrown away, so both just add 1. Module 2, lesson 02, shows where
i++and++idiffer, which is only when you use the value.What happens when n is 0?
The test fails at its first check, and the body runs zero times. That is correct behaviour, not an error, and a program should still print what an empty input needs, as Zara would check first.
Are
for...ofandfor...inthe same loop?No.
for...ofhands you values.for...inhands you the names of an object's properties, and on an array it hands you the positions as strings. Lesson 02 shows both and the trap between them.
Key takeaways
ifruns its block when the condition is truthy, andelseruns its block when it is falsy; this track always writes the braces.- A
forloop runs its start once, its test before every pass and its step after every pass. - A loop ends the first time its test is falsy; a test that is falsy at once means zero passes.
- A
letdeclared in a loop's start lives only inside that loop; keep results in variables declared before it. for...oftakes one value per pass from an array or a string, with no counter to manage.- Go deeper: Under the Hood, loops as jumps, the iterator protocol and a loop lab (Pro).
Next, lesson 02 takes every statement one at a time: else if, switch, while, do...while, for...in, break and continue.
End of lesson 1
Mark it done, and your progress moves with you.
Next: Every Statement, One by One