Using the filter() Method in JavaScript

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 front‑end 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
filter() belongs to Array.prototype, giving it the full name Array.prototype.filter(). It calls the callback for each existing array position in order, skipping empty slots in a sparse array.
The callback's return value is tested for truthiness:
- A truthy value, including
true, keeps the element. - A falsy value, including
false,0orundefined, leaves it out.
filter() creates a new shallow array and does not itself rewrite the input. That does not make every call pure: a callback can have side effects or mutate an object. Included objects are still the same references held in the original array, so changes through either array can affect them.
Syntax
The syntax for filter() looks like this:
const array = [-2, 0, 3];
const thisValue = { minimum: 0 };
const newArray = array.filter(function (element, index, arr) {
return element > this.minimum;
}, thisValue);
console.log(newArray); // [3]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: 'XC40' },
{ brand: 'Volvo', model: 'C30' },
{ 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 numbers‑as‑strings 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:
trueif the genre field contains either 'Science Fiction' or 'Disaster';Year:
trueif 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
filter() visits the existing array positions and creates a result array. Chaining several filters can be readable, but it also adds traversals and intermediate arrays. If performance matters, measure the real predicates and data; cheap checks that reject many items can often short‑circuit more expensive checks within one callback.
Complex Conditions
A callback can combine several conditions or inspect nested properties. Returning a boolean usually makes that intent clearest, even though filter() accepts any truthy or falsy result. Keep side effects out of the predicate where you can.
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!