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
- 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?
- 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' );
}
}