Stop Array.forEach and start using filter, map, some, reduce functions.

Vikash Agarwal
Frontend Weekly
Published in
7 min readNov 18, 2017

The most common code review comments I give is, stop using forEach or _.each and start using specific methods like filter, map, reduce, some etc… it’s not just cleaner, it’s easy to understand the code as what logic is there inside the loop. It also helps you to follow functional programming and moving to libraries like RxJS becomes easy. With new arrow function in ES6, these utilities methods are very much convenient to use. Check examples below.

There are lot of advantages of using specific methods over generic forEach version.

  • It’s easy to write and others can interpret it easily
  • It’s easy to maintain, extend & test
  • You can write pure functions without any side effects
  • Helps you thinking in terms of functional programming
  • if you ever plan to use libraries like RxJS, it will surely help.

Let’s see some example.

Using Filter

Array.Filter returns a new array of elements which pass the given test functions. It loops over all the elements of the source array, calling test function for each item, if test function returns true, the element will be added to the new array. With Filter function, we can just supply the core test logic of the function, leaving rest of the work to the Filter which makes it easy to write and understand. Ex below

Example 1 :- Filter even numbers
var numberArray = [1,2,3,4,5,6,7,8,9,10];
//for Version
var evenNumbers = [];
for (var counter=0; counter < numberArray.length; counter++){
if (numberArray[counter] %2 === 0){
evenNumbers.push(numberArray[counter])
}
}
console.log(evenNumbers);
//forEach Version
var evenNumbers1 = [];
numberArray.forEach(number => {
if (number%2 === 0){
evenNumbers1.push(number)
}
})
console.log(evenNumbers1);
//filter version
var evenNumbers2 = numberArray.filter(number => number%2===0);
console.log(evenNumbers2);
// es5 style
var evenNumbers2 = numberArray.filter(function(number){
return number%2===0;
});
Example 2:- Filter objects with tags javascript
var persons = [
{id : 1, name : "John", tags : "javascript"},
{id : 2, name : "Alice", tags : "javascript"},
{id : 3, name : "Roger", tags : "java"},
{id : 4, name : "Adam", tags : "javascript"},
{id : 5, name : "Alex", tags : "java"}
];
var javscriptPersons = persons.filter(personObj => personObj.tags.indexOf("javascript") > -1);//es5 style
var javscriptPersons = persons.filter(function(personObj){
return personObj.tags.indexOf("javascript") > -1
});
console.log(javscriptPersons);

Looking at the above filter function, it becomes clear immediately that its filtering the original array based on the condition used inside the test function. With for & forEach version, need to analyze that there is an empty array defined first and then elements are added to it based on the condition. With Filter function, we only need to concentrate on the test function logic.

Check mozilla docs for more details

Using Map

Array.Map returns a new array by transforming each element of the source array to some other format based on the supplied transformation method. It loops over all the elements, calling supplied transformation function for each element and push the results in the new array. Like Array.Filter, we just need to supply the transformation function, rest of the work will be done by the Map function. For ex,

Example 1 :- find square of numbersvar numberArray = [1,2,3,4,5,6,7,8,9,10];//for Version
var squareNumbers = [];
for (var counter=0; counter < numberArray.length; counter++){
squareNumbers.push(numberArray[counter] * numberArray[counter])
}
console.log(squareNumbers);
//forEach Version
var squareNumbers1 = [];
numberArray.forEach(number => {
squareNumbers1.push(number*number);
})
console.log(squareNumbers1);
//Map version
var squareNumbers2 = numberArray.map(number => number*number);
//es5 version
var squareNumbers2 = numberArray.map(function(number){
return number*number;
});
console.log(squareNumbers2);
Example 2:- Map objects to String array having name
var persons = [
{id : 1, name : "John", tags : "javascript"},
{id : 2, name : "Alice", tags : "javascript"},
{id : 3, name : "Roger", tags : "java"},
{id : 4, name : "Adam", tags : "javascript"},
{id : 5, name : "Alex", tags : "java"}
];
var nameArray = persons.map(personObj => personObj.name);//es5 version
var nameArray = persons.map(function(personObj){
return personObj.name;
});
console.log(nameArray);

Again, looking at the map function, we only need to understand the core transformation logic. In the above example, for loop and forEach version requires extra effort to understand that it is transforming the array elements into some other format. Check Mozilla Docs to learn more.

Using Some

Array.Some is used to check if at least one element in the array passes a condition or not. Like Array.Filter, it accepts a test function where it loops through the source array’s element. It returns true if any one of the element passes the test condition. If all the elements fails on the test function, it returns false. it short circuits the loop as soon as one of element passes the test function. Ex below

Example 1 :- contains 5var numberArray = [1,2,3,4,5,6,7,8,9,10];//for Version
var hasFive = false;
for (var counter=0; counter < numberArray.length; counter++){
if (numberArray[counter] === 5){
hasFive = true;
break;
}
}
console.log(hasFive);//forEach Version
var hasFive1 = false;
numberArray.forEach(number => {
if (number === 5){
hasFive1 = true;
}
})
console.log(hasFive1);
//Some version
var hasFive2 = numberArray.some(number => number === 5);
//es5 version
var hasFive2
= numberArray.some(function(number){
return number === 5
});
console.log(hasFive2); // logs truevar hasEleven = numberArray.some(number => number === 11);
console.log(hasEleven); // logs false
Example 2:- Check for someone with java.
var persons = [
{id : 1, name : "John", tags : "javascript"},
{id : 2, name : "Alice", tags : "javascript"},
{id : 3, name : "Roger", tags : "java"},
{id : 4, name : "Adam", tags : "javascript"},
{id : 5, name : "Alex", tags : "java"}
];
var hasJava = persons.some(personObj => personObj.tags.indexOf("java") > -1);//es5 version
var hasJava = persons.some(function(personObj){
return personObj.tags.indexOf("java") > -1
});
console.log(hasJava);

Array.Some is used to test for a condition. If any element in the array passes that condition, Array.Some method will return true, else false. Again Some function is much simpler here than the “for” versions. Similar to Array.some, Array.every is also there. It returns true, if all the elements passes the test condition. Check Mozilla Docs to learn more.

Using reduce

Array.reduce is used when you want to process all the elements of an array to get a single value out of it. Reduce is little tricky one to understand in beginning but once you understand it’s really simple to use. Array.Reduce takes two arguments, one is the reduce function and second is the initial value which is called as accumulator. It calls the reduce function for each element by passing the accumulator value. Reduce function process the current element and updates the accumulator value and pass it for the next iteration. At the end of the last loop, accumulator becomes the final result. So basically it takes an array and reduce the array into single value. Lets explore with example

Example 1 :- sum of arrayvar numberArray = [1,2,3,4,5,6,7,8,9,10];//for version
var sum = 0;
for (var counter=0; counter < numberArray.length; counter++){
sum += numberArray[counter]
}
console.log(sum);//forEach Version
var sum1 = false;
numberArray.forEach(number => {
sum1 += number;
})
console.log(sum1);
//Reduce version
var sum2 = numberArray.reduce(((acc, num) => acc + num), 0);
//es5 version
var sum2
= numberArray.reduce(function(acc, num){
acc += num;
return acc;
}, 0);
console.log(sum2);Example 2:- Check for someone with java.
var persons = [
{id : 1, name : "John", tags : "javascript"},
{id : 2, name : "Alice", tags : "javascript"},
{id : 3, name : "Roger", tags : "java"},
{id : 4, name : "Adam", tags : "javascript"},
{id : 5, name : "Alex", tags : "java"}
];
var uniqueTags = persons.reduce((acc, personObj) => {
acc[personObj.tags] = 1;
return acc;
},{});
//es5 version
var uniqueTags = persons.reduce(function(acc, personObj){
acc[personObj.tags] = 1;
return acc;
},{});
console.log(Object.keys(uniqueTags)); // Returns array of unique tagsExample 3:- getting single list of the cols
var categories = [{
type : "category1",
cols : ["col A", "col B"]
}, {
type : "category2",
cols : ["col C", "col D", "col E"]
}, {
type : "category3",
cols : ["col F"]
}]
var colList = categories.reduce((acc, category) => {
acc = acc.concat(category.cols);
return acc;
}, []);
var colList = categories.reduce(function(acc, category){
acc = acc.concat(category.cols);
return acc;
}, []);
console.log(colList); //logs ["Col A", "Col B", "Col C", "Col D", "Col E", "Col F"];

It’s really important to return accumulator value at the end of the reduce method. Otherwise acc will be undefined for the next iterator. Array.ReduceRight is another flavor of Array.reduce which traverses elements from right to left. Check mozilla docs for more examples.

There are other array utilities method like every, slice, splice, concat, sort which everyone should be aware of. Using right kind of function not only make code cleaner, it makes it easy to test and extend. Plus you are writing futuristic code by using these functions. These functions are native javascript functions which are supported in all the browsers and are getting faster day by day. It also helps to compose smaller functions to create a bigger use case.

using evenNumbers and sum, we can easily fund sum of even numbersvar numberArray = [1,2,3,4,5,6,7,8,9,10];var evenNumberFilterFn = (number => number%2===0);
var squareMapFn = (number => number*number);
var sumFn = ((sum, number) => sum + number);
var sumOfSquareOfEvenNumbers = numberArray
.filter(evenNumberFilterFn)
.map(squareMapFn)
.reduce(sumFn,0);
console.log(sumOfSquareOfEvenNumbers)

Now lets say we have to write another function to sumOfSquareofOddNumbers. We need to write only odd number filter function and rest can be used from above
var oddNumberFilterFn = (number => number%2 !==0);
var sumOfSquareOfOddNumbers = numberArray
.filter(oddNumberFilterFn)
.map(squareMapFn)
.reduce(sumFn,0);
console.log(sumOfSquareOfOddNumbers);

Check out array docs for full list of Array functions.

Note on Performance :-

Array.filter, map, some has same performance as forEach. which is slower than for/while loop. Unless you are working on performance critical functionalities, it should be fine using above methods. With JIT, Javascript execution engines are very fast and its getting even faster day by day. So start taking advantages of these methods in your application.

Thank you for reading my article. If you think its useful, please share, like, clap, comment :-)

--

--