8 min. read

November 22, 2021

JavaScript

JavaScript Array Filter in The Real World

filter()is an array method that allows us to create a new array out of another with all elements that meet a condition we supply.

syk-houdeib

Syk Houdeib, Front-end developer

const products = ['beans', 'pizza', 'chicken', 'salmon'] // Filter all products called pizza const filteredProducts = products.filter(product=> product === 'pizza') console.log(filteredProducts) // ['pizza']

In this “JavaScript iteration in the real world” series of articles, I want to share with you some of the most common JavaScript iteration methods using examples that resemble as closely as possible what their usage looks like in the real world. I will try to avoid examples with foo and bar or overly complex examples. There won’t be a lot of mentions of your pets and friends either I’m afraid. Instead, we’ll take a deep look at how the method works, why we need it, and what it would look like in a typical modern front-end codebase.

Array filter()

In this article, we are exploring the Array.filter() method; a very commonly used and helpful method. It takes an array of elements and returns a new array with only those elements that meet whatever condition we supply it with. 

So in the example, above we have an array of products and we used the filter() to filter out everything that isn’t a pizza and keep just the pizza. Let’s take a closer look at it. What does this line mean?

const filteredProducts = products.filter(product => product === 'pizza')

In plain English, this line of code means: given an array called products, take each element in the array and check if it exactly matches the string “pizza”. If it doesn’t discard it, and if it does add it to a new array. When finished, store the new array in a variable called filteredProducts. That’s it, that’s what this means in simple terms.

But this is not a very realistic example here, and we are all about the “real world” vibe. So let’s try to do that.

In the real world

Let’s create a realistic context on which to base our examples. Imagine if you are working on the codebase for an online shop. The shop sells products from several markets.

JavaScript iteration in the real world

So instead of filtering one specific product called pizza, in this example, our products come from different markets and we want to filter only the products that are from the “Great Mall”.

I have set up a simple app to show you this in action. You can check out the web app and see the filter in action, and you can see the code in its GitHub repo. But we will go through everything here first.

Let’s think of our product for a minute. In the first example, the array only had a simple string with the name of the product. But a real physical product has many more properties that we need to model in our data. That’s why each product is an object which contains all the properties this product has, such as its name, price, and the market it comes from.

{    name: "Hearty beans",    price: "1.99€",    market: "Local Market",  }

So if instead of the condition we supply being that the element is “pizza” but instead we want to create a filter method that only shows the products from “Great Mall” it would look like this:

const filteredProducts = products.filter( (product) => product.market === 'Great Mall')

Here we dive deeper into the product and look at one of its properties and compare that to the string we provide it. If we apply this filter in our fictional online store it would look like this.

JavaScript iteration in the real world (2)

How does it work?

So how does this work? In the example above we have an array of products. All JS arrays have a set of built-in methods that we can use. filter() is one of those, and we access it with the syntax our Array.filter().

Filter is a higher-order function, that’s a fancy way of saying that it is a function we can pass another function for it to do something with. We don’t need to know how it works behind the scenes for now. The only thing we care about is that within its parenthesis we pass it the function that will test each element in the array to decide if they’re being kept or discarded. 

Filter will then pick up each individual element of the array and examine it against the test we provided. The current element that filter is looking at is provided to us as the first argument. That’s the first “product” we see. It is a variable that we can name whatever we want. But it’s logical that for an array of products a single element is one “product”, just as for an array of songs we would call the variable “song”.

products.filter( (product) => product.market === 'Great Mall') songs.filter( (song) => song.title === 'What’s Up?')

After the arrow of the arrow function, we use the “product” variable to implement the test we want. And filter does the rest. It will iterate through the whole array and return an array of everything that matches our test.

It’s probably clear by now why filter() is a very commonly used method. There are a lot of times when we want to show a subset of the data available in our front-end application, whether it’s because of user actions, or some business logic. 

What’s more

We have already seen how filter provides us with one argument: the current selected element from the array, the one we called “product” in our example. It also provides us with two more predefined arguments that are useful. The second argument is the index. While the third is the array.

myArray.filter((element, index, array) => //Do stuff)

The “element” is our “product” in our example, the index is the position of this currently selected element in the array, and the final argument is actually the full array itself we are iterating on. 

For example, this is what we will get if we log each product and its index on each iteration of filter()

const products = ['beans', 'pizza', 'chicken', 'salmon']products.filter( (product, index) => console.log(product, index))// 'beans’, 0 // 'pizza’, 1 // 'chicken’, 2 // 'salmon’, 3

Two things to keep in mind. If we are working only with a single argument the parenthesis is optional, so if you see “product” without the parenthesis it’s the same thing, it just looks cleaner.

products.filter( (product) => product.market === 'Great Mall') // same as products.filter(product => product.market === 'Great Mall')

But we can only drop the parenthesis if we have one argument. We need to have them for more than one.

Secondly, we called the second argument “index” here, and the third argument “array”. But like “product” these are also variable names. You can name them what you want. You can call them “nomi” and “amanita” and nothing would change. Remember it’s not the name that matters here, but the position of the argument. The first is always the element, the second is always the index, and the third is the array we started with. However, your obscure pop culture reference notwithstanding, we tend to name things in a way that makes it easier for readability. So the second argument is almost always called “index” or “i” by convention, and the third usually is “array” or “arr”. 

So far we have only seen filter functions that are one-liners. What happens if we need to write several lines to make the comparison? Then we have to add curly braces to enclose the code and then explicitly specify what to return. In the one-liner example, the arrow function implicitly returns whatever comes after. This doesn’t happen when we have curly braces after the arrow, so we need to use “return”.

products.filter(product => {   // do stuff   return product.market === 'Great Mall' })

Another way you will see filter() being written is to store the function we are using for the test separately and then pass it as a callback function directly. This would look like this.

const isMall = product => product.market === 'Great Mall' const filteredProducts = products.filter(isMall)

What it looked like prior to ES6

Prior to the ES6 version of JavaScript, we didn’t have arrow functions, and writing the same filter function looked different syntactically. This is important to know because you will come across this way of writing it in tons of older codebases that are still in use, and you will come across it in older examples on Stack Overflow and the like.

products.filter(function(product) {     return product.market === 'Great Mall' })

As you can see, before we got the arrow function we needed the “function” keyword, the arrow is gone and we need the curly braces and the “return” keyword.

What it looks like in a for loop

At the heart of all great array, methods are humble for loop doing all the actual work. It’s not often that we would need to write a for loop for something like this because filter() does the job. But seeing what this looks like in a for loop helps us remove the mystery and take a glimpse at what is actually happening behind the scenes.

function filterProducts(products) {   let filteredProducts = []   for(let i = 0; i < products.length; i++) {     if (products[i].market === ‘Great Mall’) {        filteredProducts.push(products[i])    }   }   return filteredProducts }

Summary

Armed with a deeper understanding of what filter() is and why we need it and with the context of an example from the real world I hope you come out of this with a much better understanding of it. It’s a powerful method and when combined with other methods it will allow you to do a lot of things with your data that form part of a typical front-end task.

The best way to get good at using it is to practice a lot. Open the console and try out some of these examples or even fork the GitHub project of the example and try changing things and filtering for other properties.