Warm-up · Activity 1 of 7
// B3.3 · ~30 min · Beginner
for, while and for...of
After this lesson you repeat code with a counting for loop, while and do...while, walk through arrays and strings with for...of, and write loops that stop, with no step too many.
You will be able to
- Write a counting for loop and a while or do...while loop, and trace how often each runs
- Walk through arrays and strings with for...of, and know that for...in is not for arrays
- Spot off-by-one errors and loops that never end, and make every loop stop
Predict · Activity 2 of 7
Predict before you read on: what does this print?
const colors = ["red", "green", "blue"]; for (let i = 0; i < colors.length; i++) { console.log(i, colors[i]); }Practice · Activity 3 of 7
Fill in the keyword so that the loop prints the letters a, b and c, one per line.
for (const letter ____ "abc") { console.log(letter); }for (const letter "abc") {Practice · Activity 4 of 7
Trace the loop: what does this print?
let total = 1; let steps = 0; while (total < 20) { total = total * 2; steps++; } console.log(total, steps);Practice · Activity 5 of 7
Each loop runs three times. Match each loop header to the values i takes.
Brain teaser · Activity 6 of 7
Brain teaser. The condition n < 5 is false from the start. What does this print?
let n = 10; do { console.log(n); n++; } while (n < 5); console.log("end", n);Apply · Activity 7 of 7
Mini-task. Write a rocket countdown: a for loop that prints 5, 4, 3, 2 and 1, one per line, then Liftoff!. Then use for...of over the string "go" to print it in capitals with a space after each letter, trimmed at the end: G O. Before you run it, point to the line in each loop that brings it closer to its end.
Check your work against this list
Build it yourself
Read the worked example, then write the exercises. Your code runs in your browser or on your computer and is never uploaded.
Worked example
A shopping receipt
This program works through a basket with each kind of loop. for...of adds up the prices, a counting for loop numbers the items, a while loop works out how many weeks of saving 3 EUR it takes to pay, and for...of over a string stamps the receipt. Run it, then add a price to the list or change the savings per week, and predict the lines before you run it again.
main.js
// Work through a basket with three kinds of loop.
const prices = [2.5, 4, 1.25, 3];
const word = "paid";
let total = 0;
for (const price of prices) {
total += price;
}
console.log("Items:", prices.length, "Total:", total);
for (let i = 0; i < prices.length; i++) {
console.log(`Item ${i + 1}: ${prices[i]} EUR`);
}
let saved = 0;
let weeks = 0;
while (saved < total) {
saved += 3;
weeks++;
}
console.log("Saving 3 EUR a week takes", weeks, "weeks");
let stamp = "";
for (const letter of word) {
stamp += letter.toUpperCase() + ".";
}
console.log(stamp);
Run it with
node main.jsOutput
Items: 4 Total: 10.75
Item 1: 2.5 EUR
Item 2: 4 EUR
Item 3: 1.25 EUR
Item 4: 3 EUR
Saving 3 EUR a week takes 4 weeks
P.A.I.D.- for...of hands over each price in turn; total += price adds it to the running total.
- i starts at 0 because positions do, so the item number is i + 1.
- The while loop stops as soon as saved, 12, is no longer below 10.75: four weeks.
- for...of over a string gives one character per pass.
Change it and run it
Tab indents and Shift+Tab outdents. To leave the editor with the keyboard, press Esc, then Tab.
The first run downloads the JavaScript runner (up to 0.1 MB) and keeps it cached. Your code runs in your browser’s own engine and stays on your device.
Exercises
Exercise 1 of 2
Welcome every guest
The program should greet each guest on the list and then print the number of guests: Welcome, Ada!, Welcome, Grace!, Welcome, Linus! and 3 guests. It skips Ada and greets someone called undefined instead. Fix the start and the condition of the for loop, and keep the list as it is.
Tab indents and Shift+Tab outdents. To leave the editor with the keyboard, press Esc, then Tab.
The first run downloads the JavaScript runner (up to 0.1 MB) and keeps it cached. Your code runs in your browser’s own engine and stays on your device.
Hints
Hint 1
Positions in an array start at 0. Which position does the loop start at?
Hint 2
guests.length is 3, but the last position is 2. What does guests[3] give?
Hint 3
Start at let i = 0 and loop while i < guests.length.
Show a solution
One way to solve it. Yours can look different and still pass the checks.
const guests = ["Ada", "Grace", "Linus"];
for (let i = 0; i < guests.length; i++) {
console.log(`Welcome, ${guests[i]}!`);
}
console.log(`${guests.length} guests`);
Run it on your computer
Install ECMAScript 2026 or newer. Save these files in one folder, open a terminal in that folder, and run the commands below.
main.js
const guests = ["Ada", "Grace", "Linus"];
for (let i = 1; i <= guests.length; i++) {
console.log(`Welcome, ${guests[i]}!`);
}
console.log(`${guests.length} guests`);
main.test.js
import {test} from 'node:test';
import assert from 'node:assert/strict';
import {runMain} from './learnrun.js';
const lines = async () => (await runMain()).trimEnd().split('\n');
test('greets Ada first', async () => {
const got = await lines();
assert.equal(got[0], 'Welcome, Ada!', `the first line is ${JSON.stringify(got[0])}, expected "Welcome, Ada!"`);
});
test('greets no one called undefined', async () => {
const got = await lines();
assert.ok(!got.includes('Welcome, undefined!'), `the program printed ${JSON.stringify(got)}`);
});
test('greets all three guests, then counts them', async () => {
const got = await lines();
assert.deepEqual(got, ['Welcome, Ada!', 'Welcome, Grace!', 'Welcome, Linus!', '3 guests'], `the program printed ${JSON.stringify(got)}`);
});
package.json
{
"type": "module"
}
package.json tells Node.js that the .js files are modules; keep it in the folder.
Run the program:
node main.jsRun the checks (needs learnrun.js in the same folder):
node --testDownload learnrun.jsExercise 2 of 2
Count and halve
Finish two loops. First, use for...of to count how many times the letter a appears in word, so the program prints a appears 3 times. Then use a while loop that halves value (divides it by 2) until it is below 1, counting each halving, so the program prints 7 halvings. Make sure your while loop changes value on every pass.
Tab indents and Shift+Tab outdents. To leave the editor with the keyboard, press Esc, then Tab.
The first run downloads the JavaScript runner (up to 0.1 MB) and keeps it cached. Your code runs in your browser’s own engine and stays on your device.
Hints
Hint 1
for (const letter of word) gives b, a, n, a, n, a. Inside, an if can test letter === "a" and add 1 to count.
Hint 2
The while condition says when to keep going: while (value >= 1).
Hint 3
Inside the while block, value = value / 2; and halvings++; bring the loop closer to its end on every pass.
Show a solution
One way to solve it. Yours can look different and still pass the checks.
const word = "banana";
let count = 0;
for (const letter of word) {
if (letter === "a") {
count++;
}
}
console.log(`a appears ${count} times`);
let value = 100;
let halvings = 0;
while (value >= 1) {
value = value / 2;
halvings++;
}
console.log(`${halvings} halvings`);
Run it on your computer
Install ECMAScript 2026 or newer. Save these files in one folder, open a terminal in that folder, and run the commands below.
main.js
const word = "banana";
let count = 0;
// Count each "a" in word with for...of.
console.log(`a appears ${count} times`);
let value = 100;
let halvings = 0;
// Halve value with a while loop until it is below 1, counting the halvings.
console.log(`${halvings} halvings`);
main.test.js
import {test} from 'node:test';
import assert from 'node:assert/strict';
import {runMain} from './learnrun.js';
const lines = async () => (await runMain()).trimEnd().split('\n');
test('counts the letter a in banana', async () => {
const got = await lines();
assert.equal(got[0], 'a appears 3 times', `the first line is ${JSON.stringify(got[0])}, expected "a appears 3 times"`);
});
test('halves 100 until it is below 1', async () => {
const got = await lines();
assert.equal(got[1], '7 halvings', `the second line is ${JSON.stringify(got[1])}, expected "7 halvings"`);
});
test('prints exactly two lines', async () => {
const got = await lines();
assert.equal(got.length, 2, `the program printed ${got.length} line(s), expected 2`);
});
package.json
{
"type": "module"
}
package.json tells Node.js that the .js files are modules; keep it in the folder.
Run the program:
node main.jsRun the checks (needs learnrun.js in the same folder):
node --testDownload learnrun.jsCommon mistakes
const as the counter of a for loop
for (const i = 0; i < 3; i++) {
console.log(i);
}
What Node.js prints
TypeError: Assignment to constant variable.Why, and the fix
The first pass works and prints 0, but then i++ tries to give the constant i a new value, and the program stops. A counting for loop changes its counter, so declare it with let: for (let i = 0; i < 3; i++). const is right in for...of, where each pass gets a new variable.
One pass too many
const items = ["tea", "milk", "bread"];
for (let i = 0; i <= items.length; i++) {
console.log(items[i].toUpperCase());
}
What Node.js prints
TypeError: Cannot read properties of undefined (reading 'toUpperCase')Why, and the fix
The three items print, then the loop runs once more with i = 3. items[3] does not exist, so it is undefined, and undefined has no toUpperCase. The last position is length - 1, so the condition must be i < items.length. Or use for...of, which has no positions to get wrong.
for...of over a number
for (const n of 3) {
console.log(n);
}
What Node.js prints
TypeError: 3 is not iterableWhy, and the fix
for...of needs something with values to walk through, such as an array or a string. A number has none, so it is not iterable. To repeat something three times, use a counting loop: for (let n = 0; n < 3; n++).
JavaScript in the browser: your browser’s own engine, in a sandboxed worker. Syntax errors are located with acorn 8.18.0, MIT. Licence and source
Exit ticket
5 questions, no hints. Score 80% or more to complete the lesson.
Finish every activity above to unlock the exit ticket.