filter: Learn JavaScript's Array Methods by Building Them
For the fourth article in the series, we explore the filter method and how we can use it to get just a subset of a large array.
January 4, 2021 | 7 minute readAs we’ve seen with our implementation of map
, creating a subset of an array is a very common task in JavaScript. With map
, we transform every item in an array. With filter
, we get a subset of an array based on some condition.
This is the fourth article in a series where I explain JavaScript’s built-in array methods, specifically focusing on how they work and how to build your own. In the 4 years I spent teaching hundreds of people how to code, I found that thinking through how these array methods work is what would ultimately make them click for people learning JavaScript. filter
is a powerful method to have in your toolbox, so let’s explore how it works.
How it Works
The filter
method takes a callback and invokes it on each item in an array. It then tests if the return value from the callback is truthy. If it is, then it will add the value to a new array. If the return value isn’t truthy, then that value is skipped. At the end, what we’re left with is all the values that returned true when passed into the callback.
For a simple example, let’s get all the even numbers from an array. In JavaScript, we know a number is even if the remainder of dividing it by two is 0 (using the modulo operator):
// Even numbers
let num = 6
if (num % 2 === 0) {
console.log(num + " is even!")
}
We can use this inside a function to test if an argument is an even number:
function isEven(num) {
if (num % 2 === 0) {
return true
} else {
return false
}
}
isEven(6) // true
isEven(7) // false
Now that we have a function that tests if a number is even or odd, we can use it to test every number in an array by passing it into .filter()
:
let nums = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
let evens = nums.filter(isEven)
console.log(evens) // [ 2, 4, 6, 8, 10 ]
The .filter()
method takes our isEven
function (as a callback) and invokes it on every item in the array. If isEven
returns true
, then we add the current item to a new array; if it returns false
, then we skip the current item. When filter()
finishes looping through the nums
array, it returns the new array of all the items that returned true
when passed in to isEven
.
That’s probably a little hard to follow. So instead of explaining it more, let’s implement our own. Seeing the code will help you understand what filter
is doing better than anything else.
Implementing Our Own
To implement our own version of the filter
method, we need to define a function that does the following:
- Accept an array and a callback function as arguments
- Create a new empty array, which we’ll return at the end
- Loop through the array, invoking the callback on each item
- If the callback returns a truthy value, then add the current item to the new array
- If the callback returns a falsey value, then skip adding the current item to the new array
- When the loop is finished, return the new array
We’ll go through this step by step, starting with creating a function, called filter
, that accepts an array and a callback as arguments:
function filter(items, cb) {
// More to come here ...
}
Our first argument, items
, will be the passed in array. The second item, cb
, will be the callback. (As a side note, cb
is a common shorthand for callback in JavaScript.)
Next, we need to create an empty array, which we’ll return at the end of the function:
function filter(items, cb) {
let final = []
// More to come here ...
return final
}
You can call this array anything you like, as long as it is something that makes sense. Calling this array final
, as it will be the final result of this function, is a fairly common name in situations like this.
Now that we have our final
array, we need to create a loop that will go through each item in the items
array. We’ll use this look to pass each item in the items
array into our cb
callback.
function filter(items, cb) {
let final = []
for (let i = 0; i < items.length; i++) {
// More to come here ...
}
return final
}
Within this loop, we want to invoke our callback function (cb
) on the current item in the loop:
function filter(items, cb) {
let final = []
for (let i = 0; i < items.length; i++) {
// Get the current item
let currentItem = items[i]
// Pass it into `cb`
let res = cb(currentItem)
// More to come here ...
}
return final
}
We’re now getting the current item from the items
array (based on the index value of i
) and passing it into the callback (cb
). We capture the return value of cb
in the variable res
. You can also call this variable anything, though res
is fairly common here too (it’s short for result).
We’re almost finished. All that’s left is to test the return value (res
) to see if it’s truthy or not. If it is, we’ll add it to the final
array, and if it’s falsey, we’ll skip it:
function filter(items, cb) {
let final = []
for (let i = 0; i < items.length; i++) {
let currentItem = items[i]
let res = cb(currentItem)
if (res) {
final.push(currentItem)
}
}
return final
}
That’s it! That’s all we need to do. We don’t need an else
because we don’t want to do anything if res
is falsey. We wouldn’t have anything to put in an else
block!
We can test out our own filter
method using the isEven
function that we defined above:
let nums = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
let evens = filter(nums, isEven)
console.log(evens) // [ 2, 4, 6, 8, 10 ]
We get the same result. Let’s also test it out with a function that gets the odd numbers:
function isOdd(num) {
if (num % 2 !== 0) {
return true
} else {
return false
}
}
let odds = filter(nums, isOdd)
console.log(odds) // [ 1, 3, 5, 7, 9 ]
You can see here that it works with our isOdds
function as well.
filter
in Action
The filter
method is easily the best way to get a subset of a list, which is a fairly common task in JavaScript development. One place that I use it a lot is to get a section of an API response.
Let’s look at an example. Let’s say we’re building an application for managing candidates who’ve applied for a job. To do that, we want to be able to filter, within the user interface, for developers with certain experience levels and skills. We might have a page in the application that looks something like this:
The left sidebar has some filters (in this case, experience and programming languages). When someone clicks on one of these filters, the contents of the main area of the screen should change to only those that match these filters. We can use the filter
method for that.
If the data we get back from the API looks like this:
const developers = [
{
name: "Antonio",
experience: "Junior",
language: "JavaScript"
},
{
name: "José",
experience: "Senior",
language: "JavaScript"
},
{
name: "Carmen",
experience: "Junior",
language: "Python"
},
{
name: "Mercedes",
experience: "Junior",
language: "JavaScript"
},
{
name: "Ana",
experience: "Junior",
language: "JavaScript"
},
]
Then we can filter for all the junior developers with something like this:
function isJunior(developer) {
if (developer.experience === "Junior") {
return true
}
return false
}
const juniorDevelopers = developers.filter(isJunior)
This will give us Antonio, Carmen, Mercedes, and Ana.
We could do something similar for JavaScript developers:
function knowsJavaScript(developer) {
if (developer.language === "JavaScript") {
return true
}
return false
}
const javascriptDevelopers = developers.filter(knowsJavaScript)
Our javascriptDevelopers
array now has Antonio, José, Mercedes, and Ana in it.
And if we want to filter
for junior developers and JavaScript developers, we can do that too:
const currentDevelopers = developers.filter(function (developer) {
if (
developer.language === "JavaScript" &&
developer.experience === "Junior
) {
return true
}
return false
})
All that would be left now to build out our page in the candidate tracking app is to render this array of developers to the screen!
Conclusion
I’ve now covered four of JavaScript’s built-in array methods. If you haven’t already, definitely check out the other articles in this series:
I’m going to go through and explain and implement every built-in array method. If you’re struggling to learn them, or just want to learn more about JavaScript in general, then be sure to follow along by signing up for my newsletter and following me on Twitter.