The Array.filter Method in JavaScript

Published: Friday, May 27, 2022
Updated: Tuesday, June 7, 2022

Greetings, friends! In this tutorial, I will discuss the Array.filter method in JavaScript.

javascript
Copied! ⭐️
const array = ['pizza', 'donut', 'pumpkin pie', 'chocolate pie'];

const newArray = array.filter(food => food.includes('pie'));

console.log(newArray);
// OUTPUT: ['pumpkin pie', 'chocolate pie']

The filter method will filter out data in array using a callback function. It will return a new array containing elements that satisfy a condition in the provided function. In the example above, we are checking if one or more elements in the array contains the string, pie. If so, then return a new array with all the elements that satisfy the condition.

Let's look at the Array.filter method's documentation more closely. According to MDN, this method can accept two parameters and returns a new array with each element being the result of the callback function.

javascript
Copied! ⭐️
filter(callbackFn, thisArg)

Notice that this function definition is very similar to Array.forEach and Array.map.

The first parameter - callbackFn

The first parameter we pass into the filter method is a callback function, and the second parameter is thisArg, a value to use as the this context when executing callbackFn. It's really rare to use the second parameter. It's also an optional parameter. Let's just look at the first parameter, the callback function. We'll discuss the second parameter later.

The Array.filter method expects a callback function that has one, two, or three parameters. The second and third parameters are optional.

javascript
Copied! ⭐️
filter((element) => { /* ... */ })
filter((element, index) => { /* ... */ })
filter((element, index, array) => { /* ... */ })

Using a Callback Function with One Parameter

Let's use the Array.filter method with a callback function that has one parameter.

javascript
Copied! ⭐️
const array = [1, 2, 3, 4, 5];

const newArray = array.filter(num => {
  return num > 3;
})

console.log(newArray);
// OUTPUT: [4, 5]

The code snippet above passes in an arrow function as a callback function. We could have just as easily defined our own function and pass that into the filter method instead.

javascript
Copied! ⭐️
const array = [1, 2, 3, 4, 5];

function filterNumbers(num) {
  return num > 3;
}

const newArray = array.filter(filterNumbers);
console.log(newArray);
// OUTPUT: [4, 5]

It's very common to use the filter method to extract one or more objects from an array of objects such that the objects have a certain value on one of its keys. Let's look at an example.

javascript
Copied! ⭐️
const array = [
  {
    name: 'pizza',
    category: 'dinner'
  },
  {
    name: 'cake',
    category: 'dessert'
  },
  {
    name: 'donuts',
    category: 'breakfast'
  },
  {
    name: 'pancakes',
    category: 'breakfast'
  }
]

const newArray = array.filter(food => {
  return food.category === 'breakfast'
});
console.log(newArray);
/* OUTPUT:
[
  {
    name: 'donuts',
    category: 'breakfast'
  },
  {
    name: 'pancakes',
    category: 'breakfast'
  }
]
*/

In the code snippet above, we are filtering through all the objects in the array such that the category property is equal to breakfast using the strict equality operator.

This is, of course, a silly example. We can eat any type of food for breakfast, lunch, and dinner! Nothing is stopping us! 🍕🍰🍩🥞

Using a Callback Function with Two Parameters

Let's now take a look at using the filter method with a callback function that has two parameters. The second parameter will be the index of the element of the array.

javascript
Copied! ⭐️
const array = ['apples', 'oranges', 'pineapples', 'bananas'];

const newArray = array.filter((fruit, index) => {
  return index % 2 === 0;
})

console.log(newArray);
// OUTPUT: ['apples', 'pineapples']

In the code snippet above, we are creating a new array and grabbing only the elements with indices that are even numbers using the remainder operator. apples is at index 0, and pineapples is at index 2. Therefore, newArray will only contain those strings.

Again, we can define a function and pass that into filter as a callback:

javascript
Copied! ⭐️
const array = ['apples', 'oranges', 'pineapples', 'bananas'];

function filterEvenIndices(fruit, index) {
  return index % 2 === 0;
}

const newArray = array.filter(filterEvenIndices);

console.log(newArray);
// OUTPUT: ['apples', 'pineapples']

Using a Callback Function with Three Parameters

Next, let's try using a callback with three parameters. The third parameter will be the array we're calling the filter method on.

javascript
Copied! ⭐️
const newArray = [1, 3, 5, 7, 9].filter((num, index, thisArray) => {
  return num > thisArray.length;
});

console.log(newArray);
// OUTPUT: [7, 9]

In the code snippet above, the parameter, thisArray, refers to a reference to the array we're calling the filter function on. They are equivalent, which means that thisArray will have a length of 5. For each element in the array, we will test if the value is greater than the length of thisArray. The filtered array, newArray will contain the values 7 and 9, since they are the only values greater than 5.

You can also shorten the code snippet above by using the concise version of arrow functions.

javascript
Copied! ⭐️
const newArray = [1, 3, 5, 7, 9].filter((num, index, thisArray) => num > thisArray.length);

console.log(newArray);
// OUTPUT: [7, 9]

The second parameter - thisArg

We have now seen how to use the filter method with a callback function with one, two, and three parameters. However, the callback function was only the first parameter we can pass into the filter method. It also accepts a second parameter, thisArg, which is optional.

As mentioned previously, it's rare to use this second parameter. You'll typically see it when people are implementing a complex feature or trying to support old legacy code. Let's see an example of how we might use the thisArg parameter in the filter method.

javascript
Copied! ⭐️
function Player() {
  this.spells = [];
  this.count = 0;
  this.hasHeal = false;
}

Player.prototype.add = function (array) {
  this.spells = array.filter((element) => {
    this.count++;
    if (element.includes('heal')) this.hasHeal = true;
    return element.includes('v2');
  }, this);
};

const nate = new Player();
nate.add(['fireball v1', 'fireball v2', 'thunderbolt v2']);
console.log(nate.spells); // ['fireball v2', 'thunderbolt v2']
console.log(nate.count); // 2
console.log(nate.hasHeal); // false

const sam = new Player();
sam.add(['blizzard v1', 'blizzard v2', 'heal v2']);
console.log(sam.spells); // ['blizzard v2', 'heal v2']
console.log(sam.count); // 3
console.log(sam.hasHeal); // true
warning
Arrow functions do not bind their own this context and will use their parent scope instead. Assigning an arrow function to Player.prototype.add will cause an error.

In the above code snippet, we are creating a Player object by calling a function. Before JavaScript introduced the concept of classes, it was common to make objects using functions and assigning properties to them using the this keyword.

Since JavaScript is a prototypal language, we can add methods to the player's prototype. Within the Player.prototype.add method, we are calling filter and passing a value of this as the second parameter. In this context, the this keyword refers to the Player prototype. This allows us to add update properties on instances of our Player object. In our example, we have two instances: nate and sam.

When we run nate.add(['fireball v1', 'fireball v2', 'thunderbolt v2']), the player, "nate," will have each "spell" added to the list of spells but only if they contain v2 (version 2). The spell count will be updated to match the total number of elements in the array. If one of the spells contains the word, heal, then the hasHeal property will be set to true.

The above code snippet may not seem like a clean approach, but it could be considered performant, since we only have to iterate through the array once to update multiple properties on a single Player object. However, there are much cleaner ways to write this code.

Conclusion

This has been a comprehensive guide to the filter method in JavaScript. In summary, the filter method accepts similar parameters as the forEach and map methods. However, the filter method returns a new array that contains elements that pass a test specified by the provided function. This method accepts two parameters: a callback and a value to use as the this context when executing the callback. The callback function can accept three parameters: the current element being processed, the index of that element in the array, and the array filter was called upon.

The filter method is a great way to filter through data returned to you from an API call or database. Just like the map method, the filter method is a very powerful tool to have in your JavaScript tool belt.

Resources