Using the filter() Method in JavaScript

Hero image for Using the filter() Method in JavaScript. Image by Simone Hutsch.
Hero image for 'Using the filter() Method in JavaScript.' Image by Simone Hutsch.

It's funny; after decades of working in web development, one of the things that I still always have to do a quick Google to check on is how you filter an array of objects based on a property of that object. And it's something that crops up very regularly in frontend development...

So today, I intend to write about JavaScript's filter()in the hopes that this time around, its syntax will sink in, and if not, at least I'll know where to look for a quick sanity check next time!


Understanding filter()

JavaScript's filter() method is what we need to filter an array of objects based on an object's property. It allows us to create a new array filled with the elements from the first array that pass a specific test. Essentially, generate a subset of the first array for objects that return true for a given condition, which is great for filtering data (the clue was in the name really wasn't it?).

Fundamentals

The filter() function belongs to the Array prototype (making it's full moniker Array.prototype.filter()), which means that it is available on any array object. It accepts a callback function as its argument, which it then calls for each element within the array.

The callback function must return a boolean:

  • true indicates that the element will be included in the new array;
  • false means it will not.

filter() is a pure function, which means the original array remains unchanged, and there are no side effects or mutations on the original data.

Syntax

The syntax for filter() looks like this:

const newArray = array.filter(function(element, index, arr), thisValue);

This can be broken down like this:

  • element: The current element being processed in the array;
  • index (optional): The index of the current element being processed;
  • arr (optional): The array filter was called upon;
  • thisValue (optional): A value to use as this when executing the callback.

A Simple Example

As a simple example, and one of the use cases I came across on a previous project, say we have a dataset that contains car makes and models. We could use filter() to extract a subset of this data to find only models built by a specific manufacturer:

const cars = [  { brand: 'Audi', model: 'A3' },  { brand: 'Volvo', model: 'XC40' },  { brand: 'Audi', model: 'Q2' },  { brand: 'Volvo', model: 'C30' },  { brand: 'Volkswagen', model: 'Polo' },  { brand: 'Audi', model: 'RS5' },  { brand: 'Volvo', model: 'S60' },  { brand: 'Volkswagen', model: 'Tiguan' },  { brand: 'Volkswagen', model: 'Golf' },];const volvoCars = cars.filter(({ brand }) => brand === 'Volvo');console.log(volvoCars);/*  Output:  [    { brand: 'Volvo', model: 'C30' },    { brand: 'Volvo', model: 'XC40' },    { brand: 'Volvo', model: 'S60' }  ]*/

Here, we iterate over the cars array and include only those cars in volvoCars where the brand model is 'Volvo'. What comes out the other side is an array of three cars made by Volvo.

I should mention here that I've also opted to use destructuring in the example above where we reference brand directly. This could just as easily be written like this:

const volvoCars = cars.filter((car) => car.brand === 'Volvo');

A More Complicated Example

For the sake of full disclosure, this is actually a task I have often set for candidates during interviews.

The Challenge

We have an array of books; these should be filtered to generate an array of books from this dataset, which are either in the 'Science Fiction' or 'Disaster' genre and should be published after 1900.

The Dataset

const books = [  {    title: 'The War of the Worlds',    author: 'H.G. Wells',    genres: ['Science Fiction', 'Disaster'],    year: 1898,  },  {    title: 'The Martian',    author: 'Andy Weir',    genres: ['Science Fiction'],    year: 2011,  },  {    title: 'Dune',    author: 'Frank Herbert',    genres: ['Science Fiction'],    year: 1965,  },  {    title: 'The Road',    author: 'Cormac McCarthy',    genres: ['Fiction', 'Dystopian'],    year: 2006,  },  {    title: 'On the Beach',    author: 'Nevil Shute',    genres: ['Science Fiction', 'Disaster'],    year: 1957,  },  {    title: 'Pride and Prejudice',    author: 'Jane Austen',    genres: ['Fiction', 'Romance'],    year: 1813,  },  {    title: 'The Hobbit',    author: 'J.R.R. Tolkien',    genres: ['Fantasy'],    year: 1937,  },  {    title: 'Seveneves',    author: 'Neal Stephenson',    genres: ['Science Fiction'],    year: 2015,  },];

For the sake of simplicity, we assume this data is typed, so there's no attempt to trip up the candidate with numbersasstrings or optional data:

title: string;author: string;genres: ('Science Fiction' | 'Fantasy' | 'Fiction' | 'Romance' | 'Disaster' | 'Dystopian')[];year: number;

The Solution

This is where an understanding of filter() and how to structure conditions becomes important.

const filteredBooks = books.filter(  (book) =>    (book.genres.includes('Science Fiction') ||      book.genres.includes('Disaster')) &&    book.year > 1900);

As I mentioned above, you could also use destructuring here:

const filteredBooks = books.filter(  ({ genres, year }) =>    (genres.includes('Science Fiction') || genres.includes('Disaster')) &&    year > 1900);

Explanation

Regardless of whether you choose to destructure or not, what we're doing in both cases is using a callback function for the filter() which checks for:

  • Genre:

    true if the genre field contains either 'Science Fiction' or 'Disaster';
  • Year:

    true if the year is larger than 1900.

If both checks are true, then the book meets our requirements and is included in the filteredBooks array. Notably, the result won't include:

  • The Hobbit

    : it's the wrong genre;
  • Pride and Prejudice

    : also the wrong genres;
  • The War of the Worlds

    : it was published before 1900.

If you're faced with this at interview, then you'll get bonus points if you can tell me whether you prefer The Martian or Seveneves. There's no right answer, although I am sore that Seveneves hasn't yet been picked up for the Blockbuster treatment...


Tips for Using filter()

Chaining Methods

filter() can be chained with other array methods like map() and reduce() for more complex operations.

Performance

Whilst filter() is convenient, it is worth remembering that it iterates over every item within the entire array. For large datasets, this could potentially cause performance issues, so it may be worth considering how these larger datasets can be filtered in a performant way. Often, I find, by filtering in stages.

Complex Conditions

As long as it returns a boolean, the callback function can contain any logic at all. This means that you can write some really complex filtering criteria, evaluating against multiple properties, or even against nested properties of the objects.


Wrapping up

Hopefully, having written this all out, I won't need to go check Google next time I need to filter a dataset... Hopefully, you won't either!


Categories:

  1. Development
  2. ES6
  3. Front‑End Development
  4. Guides
  5. JavaScript