There are several different ways to loop through elements in an array. Most likely, you will see for
, forEach
, for..in
, and for..of
. These 4 (pseudo pun intended here) are often confused and that's what we are going to fix 💪
In many older codebases and code examples online, you will see the ubiquitous for
loop used to iterate over an array. The typical setup initializes a variable i
to 0 (because we want to start with the zeroth element). The second statement defines how many times the loop will run, most often you'll iterate over every element in the array - so i < array.length
. And the 3rd statement increasing i
on every pass. This allows us to access each element in the array by its index and perform something.
Here, we are just logging the score to the console:
const scores = [82, 89, 90, 94, 81];
for (let i = 0; i < scores.length; i++) {
console.log(scores[i]);
}
> 82
> 89
> 90
> 94
> 81
In more modern codebases, however, you will see a mix of forEach
, for..in
, and for..of
. The most common scenario you will encounter is that you want to iterate over every element in the array and execute something using that element. So which do you choose?
Let's start with a more concise version of what the for
loop gives us. With for..of
, we are able to quickly access each element without having to keep track of the index or worry about incrementing/decrementing the index.
const scores = [82, 89, 90, 94, 81];
for (const score of scores) {
console.log(score);
}
> 82
> 89
> 90
> 94
> 81
With forEach
, you have access to the index of the current element being iterated over, the element value, and the array itself. Sounds great, right? Well it is, and proponents of the Functional Programming paradigm greatly prefer this method of looping. forEach
expects a synchronous function, so be aware of that when using async/await
with it. You can’t use await
in the body
of this kind of loop and you can’t leave a forEach
loop early. In for
loops, we can use break
.
const scores = [82, 89, 90, 94, 81];
scores.forEach((score) => console.log(score));
> 82
> 89
> 90
> 94
> 81
The for..in
loop is meant to be used with objects, not arrays. So if you use it with an array, you will likely get some unexpected output. This is because for..in
is iterating of the enumerable properties of the object (at the end of the day, our arrays are objects).
const scores = [82, 89, 90, 94, 81];
for (const score in scores) {
console.log(score);
}
> 0
> 1
> 2
> 3
> 4
Here's a basic rundown of when to use for..of vs for..in:
<img width="100%" alt="for..in versus for..of" src="https://www.speek.dev/for..of-for..in.png" />
Now that we have a better idea of what the different types of for
loops do, let's dive into some exercises to test our newfound knowledge!
In your browser, open up the developer tools to the console tab and console log the scores that are less than 90 using the classic for
loop (not for..in
or forEach
):
const scores = [82, 89, 90, 94, 81];
// for() {} loop goes here
Now, console log the scores that are less than 90 using the forEach
loop:
const scores = [82, 89, 90, 94, 81];
// forEach loop goes here
Next, console log the scores that are less than 90 using the for..of
loop:
const scores = [82, 89, 90, 94, 81];
// for..of loop goes here
Lastly, console log the index of the scores that are 90 or greater (≥ 90) using the forEach
loop. Hint: the second argument is the index apples.forEach((apple, index) => { console.log(index) })
:
const scores = [82, 89, 90, 94, 81];
// for loop goes here
Final note on iterating over arrays
Remember when I told you that forEach
is expecting a synchronous function? Well we can also use that to our advantage when we don't want to explicitly iterate over an array's elements one-by-one. For longer running loops, you'll see the benefit of using forEach
vs reaching for for..of
Let's take our scores and loop over them using forEach
. If we pretend that we have some longer running code in there using async/await
, you'll notice that the console.log(score)
doesn't wait for it. This can be a useful tool to take advantage.
const scores = [82, 89, 90, 94, 81];
scores.forEach(async (score) => {
await new Promise((resolve) => setTimeout(resolve, 500)); //fake long running code
console.log(score);
});
To contrast, for..of
will wait for that longer running code to finish before moving on to our console.log(score)
:
const scores = [82, 89, 90, 94, 81];
for (let score of scores) {
await new Promise((resolve) => setTimeout(resolve, 500)); //fake long running code
console.log(score);
}
These are basic examples of running in sequence versus running in parallel. If you're needing to run in sequence, reach for for..of
in this case. If you are able to run in parallel (you don't need to wait for that longer running process), try using forEach
instead.
For more information on the asynchronous version of for..of
, see this post on for await..of
👀
Wanna get better at working with arrays in JS? Check out my free course 🔥