Skip to content

All the for loops in JS

All the For Loops

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 🔥