What a for...of loop does
A for...of loop runs a block of code once for each item of a collection, such as an array or a string. You name a loop variable, and on every pass it holds the next item. Compared with writing one statement per item, the code stays the same size however long the collection is.
Looping through a string
A string is a sequence of characters, so a loop can visit them one by one:
const word = "Andy";
for (const letter of word) {
console.log(letter);
}
The output is:
A
n
d
y
The pieces of the loop header are:
forstarts the loop.letteris the loop variable. It takes the value of each item in turn.ofseparates the loop variable from the collection.wordis the collection to walk through.
The statements between the curly braces are the loop body. They run once per item, and inside them letter holds the current character.
Looping through an array
The same shape works for arrays, where the loop variable holds each element:
const fruits: string[] = ["banana", "orange", "pear", "kiwi"];
for (const fruit of fruits) {
console.log("I eat " + fruit);
}
I eat banana
I eat orange
I eat pear
I eat kiwi
This is the loop that replaces the four repeated console.log lines from the previous lesson. With a hundred fruits, only the array changes.
Why const works in the header
The value of fruit is different on every pass, which may make const look wrong. It isn't: each pass of the loop creates a fresh variable for that pass, and const only stops you from reassigning it inside the body. Use const by default and switch to let only if the body needs to reassign the loop variable. Trying fruit = "x" inside a const loop is reported as an error.
Do not confuse of with in
JavaScript has a second loop, for...in, that looks almost the same. It does not give you the items. It gives you the keys of an object, and for an array those are the index numbers as strings:
const fruits: string[] = ["banana", "orange"];
for (const x of fruits) console.log(x); // banana, then orange
for (const x in fruits) console.log(x); // 0, then 1 (as strings)
When you want the elements of an array, use of.
The lesson's exercise
The starting code has an array of friends. The task is to greet each one with a loop.
- Write the loop header. Use
for...ofwith aconstvariable namedfriendand the collectionfriends. - Print inside the body. Use
console.logwith a template literal, the backtick string that inserts a value where${friend}appears, to printHey,followed by the name and an exclamation mark.
const friends: string[] = ["Andy", "Mary", "John"];
for (const friend of friends) {
console.log(`Hey, ${friend}!`);
}
The output is:
Hey, Andy!
Hey, Mary!
Hey, John!
The template literal is written with backticks, not quotes, and the expression inside ${ } is replaced by its value. It does the work of "Hey, " + friend + "!" with less clutter. If the array had ten more names, the loop would greet them all without any change.
Gotchas
- The loop variable is a copy of the item for that pass. Reassigning it does not change the array.
- You don't get the index. If you need the position too, loop over
friends.entries()withfor (const [i, friend] of friends.entries()), or use a counting loop withfriends[i]. - An empty array runs the body zero times. No error, and nothing printed.
- Strings are visited by code point. An emoji counts as one item for
for...ofeven though it takes two units in the string'slength. - Only collections can be looped over. A number is not iterable, so
for (const x of 5)is reported by the compiler and fails when run.
Key takeaways
for (const item of collection) { ... }runs the body once per item.- The loop variable holds the current item, and inside the body you can use it like any other variable.
- Template literals such as
`Hey, ${friend}!`build messages from values. - Use
offor items and notin, which gives keys.