David Wampamba

3 minutes read

When not to use a forEach loop in JavaScript

A forEach loop is one of the most optimized JavaScript Higher-Order functions that make it one of the preferred functional programming languages.

What is a Higher-Order function?

It is a function which takes in another function (also called a callback) as a parameter or returns a function.

What is a forEach in JavaScript?

It a function used to iterate or loop over array elements. It accepts a callback back function which it calls for every element in the array in ascending order and an optional value to be used in the place of the this keyword while calling/invoking the callback. The forEach Higher-Order function returns undefined value.

What is the Syntax?

arr.forEach(callback(currentValue [, index [, array]])[, thisArg]);
arr represents the array to be looped. Example of array below.
let names = ['David','Harriet','Ronald','Laurence']; 

or – the old way.

let names = new Array('David','Harriet','Ronald','Laurence'); 

callback – The function to be called on each element in the array. The callback can be a named function or anonymous function. The callback itself accepts 3 parameters of which 2 are optional. In fact, I personally use them and I think most programmers rarely use them too, speaking from experience of the code, I looked at from other developers.

The 3 parameters of the callback are the currentValue, Index, and the array being looped.

Use case 1: Using a named callback

const CITIES = ['Kampala', 'Lagos', 'Nairobi','Cairo', 'Kigali' ];
printCities = CITY => { console.log( CITY ); }
CITIES.forEach( printCities );

Use case 2: Using anonymous callback

const COUNTRIES = ['Uganda','Kenya','Tanzania','Nigeria'];
COUNTRIES.forEach( country => { console.log( country ) } );

WHEN NOT TO USE THE forEach FUNCTION?

How did I discover this? I was training a student and we were doing a practical project. We were mimicking a Single Page Application using vanilla JS. We had a JS object with one of the keys being users. The users key was holding an array of objects. Each user object has a name, email, and password for the user. Something like below.

...
users: [
    {name: "David",email:"student1@school.ac",password:"password"},
    {name: "Ronald", email:"student2@school.ac", password:"password"}
];

And we were picking user-provided username and password. Looping over the users’ array and comparing the user-provided details with the ones in the object. If we find the match we produce a notification that the user is found or not found if we don’t find a match.

What happened is that whenever we found the match the alert notification telling us that we have found a match, appeared and various notifications, did too. The other were notifications were as many as the elements in the array which don’t match our search.

We rushed in trying to use a break, return and continue statements but not offered the solution.

This is when we found out that the forEach doesn’t support those statements. You can break out of the forEach loop. At leaste not as simple as using the break and return statements.

Try to test it using the code below.

students: [
    {name: "David",email:"student1@school.ac",password:"password"},
    {name: "Ronald", email:"student2@school.ac", password:"password"},
    {name: "Calvin", email:"student3@school.ac", password:"password"},
    {name: "Rachel", email:"student4@school.ac", password:"password"}
];
//Looping the student to find a given match
users.forEach( student => {
    if( student.name == 'David' && student.password == 'password') {
        alert( 'Student enrolled' );
    } else {
        alert( 'Student not found' );
    }
});

The code above and below this sentence will give you similar outputs, that is to say, four alerts, i.e. one, of Student found and three, of Student not found.

students: [
    {name: "David",email:"student1@school.ac",password:"password"},
    {name: "Ronald", email:"student2@school.ac", password:"password"},
    {name: "Calvin", email:"student3@school.ac", password:"password"},
    {name: "Rachel", email:"student4@school.ac", password:"password"}
];
//Looping the student to find a given match
users.forEach( student => {
    if( student.name == 'David' && student.password == 'password') {
        alert( 'Student enrolled' );
        break;
        //return false;
    } else {
        alert( 'Student not found' );
    }
});

How can you achieve the result we wanted?

At the moment I thought of two scenarios of which we practically tested one.

a. Introduce a variable such as found and set it to true or false accordingly.

Pros

It solves the problem of producing many alerts at the user interface.

Cons

  1. But it poses a con. What if the elements were a couple of hundreds or thousands or millions why waste memory looping all of them just to find a single match?
  2. More lines of code. Since you have to introduce a variable, you also have to check it and make a decision.

Sample code below.

let isFound = false
students: [
    {name: "David",email:"student1@school.ac",password:"password"},
    {name: "Ronald", email:"student2@school.ac", password:"password"},
    {name: "Calvin", email:"student3@school.ac", password:"password"},
    {name: "Rachel", email:"student4@school.ac", password:"password"}
];
//Looping the student to find a given match
users.forEach( student => {
    if( student.name == 'David' && student.password == 'password') {
        isFound = true
    }
});

if(isFound) {
    console.log( 'Student enrolled' );
} else {
    console.log( 'Student not found' );
}

2. Use the for ( element of elements ) loop.

This solved our problem for our use case. I don’t see any cons with at the moment.

students: [
    {name: "David",email:"student1@school.ac",password:"password"},
    {name: "Ronald", email:"student2@school.ac", password:"password"},
    {name: "Calvin", email:"student3@school.ac", password:"password"},
    {name: "Rachel", email:"student4@school.ac", password:"password"}
];
//Looping the student to find a given match
for( student of students ) {
    if( student.name == 'David' && student.password == 'password') {
        alert( 'Student enrolled' );
    } else {
        alert( 'Student not found' );
    }
}

Sharing is caring

Facebook
Twitter
LinkedIn
WhatsApp
Email

You may also like this

You deserve to be there at the top.

I’m glad to present about “deserving to be there at the top” at the first WordCamp in Africa in 2023. This is a wonderful opportunity to connect and share my experience with the community. #WordCampEbbs happening now at the Uganda

Read More »
Resources

You are not about to die poor.

In recent years, the biggest number of people I have met are characterized by the following;- Lazy Not ready Entitled Ignorant Dishonest Inconsistent It sounds unfortunate, that most probably you will meet people of similar characteristics or more if you’ve

Read More »
Resources

Thoughts on 13-06-2019

I promised to share my thoughts in any possible way. In fact, am happy to be honoring you, my readers, that today by sharing something that could be life changing to some. Please, I request you to converse through the

Read More »
Resources

A beautiful thought for 29-05-2019

Hey beloved, Once in a while, I develop thoughts in my head, and instead of keeping them to myself I’ve decided to share them. Who knows who it will help? By the way, at the bottom of the post, is

Read More »
Verified by MonsterInsights