Loops and Iteration
Table of Contents
- Why Repeat Things?
- Your First Array
- The Classic for Loop
- for...of: Loop Over Values
- while and do/while
- break and continue
- The for...in Caveat
- Strings and Nested Loops
- Avoiding Infinite Loops
- Try It Yourself
1. Why Repeat Things?
Dara's profile page will show four projects. Writing the same line of code four times would work, but it breaks as soon as a fifth project arrives. Computers are good at repeating work, and a loop is how you tell JavaScript to do that: run a block of code again and again until a condition says stop.
In the last chapter you used if to choose between two paths. A loop
adds a second idea: go back and run the same path again. Almost every
program uses both.
2. Your First Array
Loops need something to loop over. The most common thing is an array:
an ordered list of values inside square brackets. Create a file named
loops.js in your dara-profile folder:
const projects = [
"Recipe Finder",
"Weather Dashboard",
"Khmer Typing Game",
"Budget Tracker",
];
console.log(projects.length);
console.log(projects[0]);
console.log(projects[projects.length - 1]);
Run it with node loops.js. You will see 4, Recipe Finder, and
Budget Tracker.
Three facts about arrays to remember:
- Each value has a position called an index, and indexes start at
0, not 1. The first project is
projects[0]. projects.lengthis the number of items, so the last index is alwayslength - 1.- A trailing comma after the last item is allowed. It makes adding new lines easier.
Chapter 6 covers arrays fully. For now, treat the array as a list that the loops below will walk through. Later, this same data will fill the project cards on Dara's page.
3. The Classic for Loop
The for loop has three parts inside its parentheses:
for (let i = 0; i < projects.length; i++) {
console.log(i + 1, projects[i]);
}
for ( let i = 0 ; i < projects.length ; i++ ) { ... }
└───┬───┘ └───────┬────────┘ └─┬─┘
start keep going if after each
this is true round
| Part | Example | When it runs |
|---|---|---|
| Initialization | let i = 0 | Once, before the loop starts |
| Condition | i < projects.length | Before every round; the loop stops when it is false |
| Update | i++ | After every round (i++ means "add 1 to i") |
The output is:
1 Recipe Finder
2 Weather Dashboard
3 Khmer Typing Game
4 Budget Tracker
The variable i is declared with let, not const, because its value
changes. By convention it is called i (for "index"), and each round
it takes the values 0, 1, 2, 3. When i becomes 4, the condition
4 < 4 is false, so the loop ends. Using < and not <= matters:
projects[4] does not exist, and you would get undefined.
The classic for loop is the right choice when you need the index,
or when you need to count in a special way, such as backwards or by
twos.
4. for...of: Loop Over Values
Most of the time you do not care about the index. You just want each
item. For that, use for...of:
for (const title of projects) {
console.log(title);
}
It reads almost like English: "for each title of projects." There is
no counter to start, test, or update, so there is less room for mistakes.
Here const is fine, because a new title is created in each round.
If you need the index as well, ask the array for pairs with entries()
and unpack them:
for (const [index, title] of projects.entries()) {
console.log(`${index + 1}. ${title}`);
}
A good rule: start with for...of. Switch to the classic for only
when you need full control of the counter. (Chapter 6 shows methods like
map and filter that replace many loops, but they are built on the
same idea.)
A loop is also how you add things up. A running total starts at zero and grows in each round:
let total = 0;
for (const n of [3, 5, 8]) {
total += n;
}
console.log(total);
This prints 16. The += operator means "add to the existing value".
5. while and do/while
A while loop repeats as long as its condition is true. It is useful
when you do not know in advance how many rounds you need.
let countdown = 3;
while (countdown > 0) {
console.log(countdown);
countdown--;
}
console.log("Go!");
This prints 3, 2, 1, then Go!. The condition is checked
before each round, so if it starts as false the body never runs.
A do...while loop checks after the round, so the body always runs
at least once:
let attempts = 0;
let number;
do {
number = attempts * 3 + 1;
attempts++;
} while (number < 8);
console.log(attempts, number);
This prints 4 10. You will rarely need do...while; it fits cases like
"ask the user for input, then ask again if it was invalid." Know that it
exists, and use for or while for everything else.
| Loop | Use it when |
|---|---|
for...of | You want each item of a list (the default choice) |
for | You need the index or a custom counter |
while | You repeat until something changes, with an unknown count |
do...while | The body must run at least once |
6. break and continue
Two keywords change how a loop runs from the inside:
continueskips the rest of this round and moves to the next one.breakstops the whole loop immediately.
for (const title of projects) {
if (title.startsWith("W")) {
continue; // skip "Weather Dashboard"
}
if (title === "Budget Tracker") {
break; // stop here, nothing after this is visited
}
console.log(title);
}
The output is Recipe Finder and Khmer Typing Game. The weather
project was skipped, and the loop ended when it reached the last one.
break is useful for searching: once you find what you want, there is
no reason to keep looking.
let found;
for (const title of projects) {
if (title.includes("Khmer")) {
found = title;
break;
}
}
console.log(found); // "Khmer Typing Game"
(Chapter 6 shows find, which does this in one line.) Use break and
continue with care. If a loop has many of them, it becomes hard to
follow, and a clearer if is usually better.
7. The for...in Caveat
JavaScript has a third loop that looks similar: for...in. It does
not give you values. It gives you the keys (names) of an object:
const levels = { html: 1, css: 2 };
for (const key in levels) {
console.log(key, levels[key]);
}
This prints html 1 and css 2, and for objects it is acceptable.
The problem is arrays. for...in on an array gives you the indexes
as strings, and it also includes any extra properties someone added
to the array:
const letters = ["x", "y"];
letters.extra = "oops";
for (const key in letters) {
console.log(typeof key, key);
}
The output is string 0, string 1, and string extra. That is
almost never what you want.
Rule: use
for...offor arrays and strings. Usefor...inonly for plain objects, and preferObject.entries()(chapter 6) even there.
8. Strings and Nested Loops
A string is also something you can loop over. for...of visits each
character:
for (const char of "Dara") {
console.log(char);
}
This prints D, a, r, a. Here is a small use, counting vowels:
let vowels = 0;
for (const char of "Mengsreang") {
if ("aeiou".includes(char)) {
vowels++;
}
}
console.log(vowels); // 3
You can also put a loop inside another loop. The inner loop runs completely for every single round of the outer loop:
const skills = ["HTML", "CSS"];
const levels = ["basic", "good"];
for (const skill of skills) {
for (const level of levels) {
console.log(`${skill}-${level}`);
}
}
The output is HTML-basic, HTML-good, CSS-basic, CSS-good: two
outer rounds times two inner rounds is four lines. Nested loops multiply
work. A loop of 1,000 inside a loop of 1,000 is a million rounds, so
keep the nesting shallow.
One more pattern you will use often is counting with an object:
const tags = ["css", "js", "css"];
const counts = {};
for (const tag of tags) {
counts[tag] = (counts[tag] ?? 0) + 1;
}
console.log(counts); // { css: 2, js: 1 }
The ?? 0 means "use 0 if there is no count yet". We use this exact idea
when Dara's page shows how many projects have each tag.
9. Avoiding Infinite Loops
If a loop's condition never becomes false, it runs forever. This is
called an infinite loop. In Node the terminal freezes; in a browser
the tab stops responding.
// DON'T run this — the condition is always true
let n = 1;
while (n > 0) {
n++;
}
The usual causes:
- You forgot the update: no
countdown--, so the number never changes. - The update goes the wrong way: counting
i--when the condition isi < 10. - The condition can never be false:
while (true)with nobreak.
A short checklist before you run any loop:
- What changes in each round?
- Does that change move the loop toward the stopping condition?
- Will the condition really become
false?
If you do get stuck, press Ctrl+C in the terminal to stop Node. In a
browser, close the tab. Nothing is broken permanently; you only need to
fix the loop and try again.
10. Try It Yourself
- Count backwards. Use a classic
forloop to print the numbers from 10 down to 1, thenLift off!. Which part of thefordo you have to change? - Number the projects. Add a fifth project to the
projectsarray and print the list as1. Recipe Finder,2. .... Did the loop need any change? - Skip and stop. Use
continueto skip every project with a title longer than 15 characters, andbreakto stop after printing two titles. (title.lengthgives the length.) - Sum the evens. Loop through the numbers 1 to 20 and add up only
the even ones. (Hint:
n % 2 === 0.) - Count letters. Loop over your own name and count how many times
the letter
aappears. Then make it work for bothaandA. (Hint:char.toLowerCase().) - Make it freeze, safely. Remove the
countdown--line from thewhileexample and run it. Stop it withCtrl+C. Then restore the line and explain in your own words why it froze.
Next, we'll package code like this into reusable functions and see how scope decides which variables each part of your program can see.
Buy Me a Coffee
Found this tutorial helpful? Consider buying me a coffee to support more free content!