Understanding JavaScript’s iterator functions

ES2015 (a.k.a ES6) brought in some interesting iterator functions that help us write less for loops. This article will go through each one, breaking them down using simple examples and comparing how a for loop might implement similar logic.

forEach()

Simple example, say we have an array of three colours and we want to go through each one and log the colour to the console. Lets look at how a for loop would implement this:

const colours = [‘red’, ‘green’, ‘blue’];
for(let i=0; i < colours.length; i++) {
console.log(colours[i]);
}
// red
// green
// blue

This type of code can sometimes be prone to error. There’s a lot of things to remember and the unusual semi colons that don’t really appear anywhere else in the language. The forEach() method simplifies this:

colours.forEach((colour) => {
console.log(colour);
})
// red
// green
// blue

It takes each element in the array and passes it to the iterator callback function. So after the first item is passed in the iterator does a console log of that item and then takes the next item in the array and so on. What I like about this forEach function is its simplicity and enhanced readability.

Here’s a more complex example — lets write an array of numbers and sum up all the numbers. With a for loop we need to create the array, a variable to hold the sum, then loop over the numbers and increment the sum variable, then finally print the sum variable. Again the forEach( ) makes this simpler with less lines of code.

const numbers = [1,2,3,4,5];
let sum = 0;
numbers.forEach((number) => {
sum += number;
});
console.log(sum); 
// 15

When using forEach you can call each iteration of the array what you like, but convention has it that you use the singular form of the array i.e. colour, number, item ect. A cleaner way to write this code is to create a separate helper function and pass this into forEach e.g. lets create a function called adder

let newSum = 0;
const adder = (number) => {
newSum += number;
}
numbers.forEach(adder);
console.log(newSum); 
// 15

Note that in forEach we don’t call the adder function like this adder(), that would immediately invoke it and pass the results in forEach, instead we want to run the adder function with each iteration of forEach and just get it to work out the sum for us.

map()

Map is probably the most popular and widely used of the JavaScript array iterators. One of the useful things about map is that it generates a new array,
leaving the original array unmodified. This is why it’s becomereally popular
to use in libraries like redux that try to avoid directly mutating or changing the original state. In the simple example below we have an array of numbers and we want to return a new array with each number doubled. lets implement this using a for loop first.

const numbers = [1,2,3];
const doubleNumbers = [];
for ( let i=0; i<numbers.length; i++ ) {
doubleNumbers.push(numbers[i]*2);
}
console.log(doubleNumbers); 
// [2,4,5]

Again using map() makes this much easier. As with forEach, map takes a callback function as an argument which does all the hard work for us.

const doubled = numbers.map((number) => {
return number * 2;
})
console.log(doubled); 
// [2,4,5]

Here’s another example. Say we want to iterate over the array and find the prices of cars. Map is great for this. In fact all over the web there’s use cases where you’ll have to render lists of data (e.g. list of tweets, list of images, list of episodes). Map is very useful for this plucking of data out of an array of objects and returning a new array.

const cars = [
{model: ‘Honda’, price: ‘cheap’},
{model: ‘Ferrari’, price: ‘expensive’},
]
const prices = cars.map((car) => {
return car.price;
})
console.log(prices); 
// [ ‘cheap’, ‘expensive’ ]

filter()

Another UI feature thats extremely popular on most sites these days is the ability to filter or sort results and data. lets imagine a list of amazon search results, each has a name and a type. Say we want to filter an array based for any electronics and return this new array.

const products = [
{name: ‘coffee machine’, type: ‘electronics’},
{name: ‘Intro to Python’, type: ‘book’},
{name: ‘Oxelo Scooter’, type: ‘Sports equipment’},
{name: ‘LG TV’, type: ‘electronics’},
{name: ‘Canon Camera’, type: ‘electronics’},
{name: ‘Fisher price monster maz’, type: ‘Kids toys’},
]

First lets do this the for loop way.

let filteredProducts = [];
for (let i=0; i<products.length; i++) {
if ( products[i].type === ‘electronics’) {
filteredProducts.push(products[i]);
}
}
console.log(filteredProducts);
// [ { name: ‘coffee machine’, type: ‘electronics’ },
// { name: ‘LG TV’, type: ‘electronics’ },
// { name: ‘Canon Camera’, type: ‘electronics’ } ]

As with the previous, the filter iterator makes this much easier with a lot less code. There’s no need for the if statement, and no boiler plate for setting up the loop.

const newFilteredArray = products.filter((product) => {
return product.type === ‘electronics’;
})
console.log(newFilteredArray);
// [ { name: ‘coffee machine’, type: ‘electronics’ },
// { name: ‘LG TV’, type: ‘electronics’ },
// { name: ‘Canon Camera’, type: ‘electronics’ } ]

Lets write a more realistic filter now. We want to filter a list of coffee machines
and return those that are in stock and under £50.

const coffeeMachines = [
{name: ‘coffee machine’, quantity: 10, price: 25},
{name: ‘coffee machine’, quantity: 2, price: 340},
{name: ‘coffee machine’, quantity: 8, price: 99},
{name: ‘coffee machine’, quantity: 4, price: 150},
{name: ‘coffee machine’, quantity: 0, price: 20},
{name: ‘coffee machine’, quantity: 0, price: 10},
{name: ‘coffee machine’, quantity: 7, price: 45},
{name: ‘coffee machine’, quantity: 23, price: 87},
{name: ‘coffee machine’, quantity: 0, price: 450},
]
const coffeeMachinesResults = coffeeMachines
.filter((coffeeMachine) => {
return coffeeMachine.quantity > 0 && coffeeMachine.price < 50;
})
console.log(coffeeMachinesResults);
//
[ { name: ‘coffee machine’,
quantity: 10,
price: 25 },
{ name: ‘coffee machine’,
quantity: 7,
price: 45 } ]

find()

This iterator is one that I would have definitely had to use a for loop to implement in the past. The purpose of find( ) is to search through an array and look for a particular element in the array, when a record is found the find helper returns that record.

Lets start off with the for loop implementation and then see how this is different with find( ). Imagine you have a list of users and you want to find the user with the name Adam

const users = [
{name: ‘Luke’},
{name: ‘Adam’},
{name: ‘Graham’},
{name: ‘Marc’},
{name: ‘Stefan’}
]
let user = ‘’;
for (let i=0; i<users.length; i++) {
if (users[i].name === ‘Adam’) {
user = users[i]
}
}
console.log(user); 
// { name: ‘Adam’ }

Now lets try this with find( ). The first thing to note is with the for loop we wrote above is it goes through the whole array even if it finds the right user. The helper function on the other hand breaks the loop as soon as it returns the found item, so in our code above it stops at the second iteration because Adam is the second name in the list. With the for loop you can fix this by using an break statement in the for loop, but an obvious drawback to using find is it will only return the first true element, so if you need more than one copy of the element returned then you can’t use find.

const foundUser = users.find((user) => {
return user.name === ‘Adam’;
})
console.log(foundUser); 
// { name: ‘Adam’ }

every() and some()

The functions every() and some() are quite similar in how they work. These helpers along with reduce which I’ll cover below take a list of elements and condense it down into a single value number or string. So slightly different to the previous helpers where we took an array and returned a single value out of the array. Lets start with an array of computers that have different amounts of RAM, we want to find if we have any of the computers in all of our stock that have 16GB of RAM. So in this case rather than getting the individual computer back, we just want a true or false if it exists. As ever we’ll start with a simple for loop and then refactor the code to use the helper functions

const computers = [
{name: ‘Macbook’, RAM: 16},
{name: ‘Dell’, RAM: 8},
{name: ‘Acer’, RAM: 32},
{name: ‘Lenovo’, RAM: 4},
{name: ‘HP’, RAM: 16}
]
let doAllComputersHAve16GB = true;
let doSomeComputersHAve16GB = false;
for (let i=0; i<computers.length; i++) {
let computer = computers[i];
  if(computer.RAM < 16) {
doAllComputersHAve16GB = false;
} else {
doSomeComputersHAve16GB = true;
}
}
console.log(doAllComputersHAve16GB, doSomeComputersHAve16GB); 
// false true

In the example above we created two flags doAllComputersHAve16GB which we set to true, and doSomeComputersHAve16GB which we initially set to false. The if statement is checking whether a computer has less than 16GB of RAM if it does then it switches the doAllComputersHAve16GB flag to false. The every( ) function works in a similar way, by iterating through the computers and evaluating the RAM against our condition, it then returns a true or false. When it gets to the end of the array it evaluates all the boolean values it returned and if there is one false it returns false for the whole set.
On the other hand if they’re all true then it returns a true. Its basically does a javascript AND evaluation over all boolean values.

const computerEvery = computers.every((computer) => {
return computer.RAM > 16;
})
console.log(computerEvery); 
// false

In our case it returns a false because the second iteration returns false. The some( ) function does an OR evaluation over all the boolean values. So its useful if you want to know whether some of the values in the array
meet a certain condition. Rhe code below will return a true value

const computerSome = computers.some((computer) => {
return computer.RAM > 16;
})
console.log(computerSome); 
// true

every( ) and some( ) actually have really useful use cases in web development, every( ) for instance can be used to ensure that a user fills in every field in a form, otherwise render an error message.

function Field(value) {
this.value = value;
}
Field.prototype.validate = function() {
return this.value.length > 2;
}
let username = new Field(‘someUserName’);
let password = new Field(‘somePassword’);
let birthdate = new Field(‘01/01/1920’);
let postcode = new Field(‘N1’);
const Fields = [username, password, birthdate, postcode];
const isFormValid = Fields.every((field) => {
return field.validate();
})
console.log(‘is form valid? ‘, isFormValid); 
// false

We can then write a function that allows the form to submitted based on what this iterator returns.

reduce()

The reduce iterator is probably the most powerful of all these functions and is extremely versatile in what it can do for you. lets start with some simple example, say you have an array of numbers and you want to get the sum. Lets first do this using a for loop.

const numbers = [20, 10, 30, 5];
let sum = 0;
for (let i=0; i<numbers.length; i++) {
sum += numbers[i]
}
console.log(sum); 
// 65

Lets now do this with reduce. It works slightly differently to the other iterators, in the call back function, along with the iterator you also have to pass an accumulator. That basically means the thing that you want to add to in each round. You have to pass a second value to reduce which is the value you want to initiate the accumulator with. If I lost you there then this example will help! So in this case the accumulator is the sum because in each iteration we want to add the number to it, and the initiator is 0.

let sum2 = numbers.reduce((sum2, number) => {
return sum2 + number;
}, 0);
console.log(sum2); 
// 65

So what the reduce function is essentially doing is condensing all the values of our array down to a single element. Lets look at another example where we want to convert an array of objects into an array of strings.

const GDSColours = [
{colour: ‘Green’},
{colour: ‘Yellow’},
{colour: ‘Grey’},
]
let convertedArray = GDSColours.reduce((accumilator, GDSColour) => {
accumilator.push(GDSColour.colour);
return accumilator;
}, []);
console.log(convertedArray);
// [ 'Green', 'Yellow', 'Grey' ]

The accumulator is just a temporary element the adds a new value to it with each iteration, you can call it what you like. Note the simple way we have written this reduce function mutates the original array, but you’ll see more sophisticated approaches to reducing data within the react and redux community where the original data is preserved.

Like what you read? Give Homam Bahrani a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.