JavaScript: Learn to filter array

JavaScript array filter method helps us to filter an array and create a new array without modifying the original array.


In my previous blog I wrote about JavaScript array map method. In this article, I will write about filter method.

filter is a non-mutating method. Filter does not affect (modify) the original array if we use this method correctly. This (does not affect) does not mean that after applying filter, the resulting array and original array elements will be the same. The resulting array will be a completely new array with different reference to the original array. The new array elements can be different than the original array. But, original array elements and reference will be unchanged.

filter

Like the map method, the filter method creates a new array with the same length from the original array. But, instead of creating an array with the same length as map, the filter method can create a new array with the same length or a smaller size array based on a condition.

filter structure:

const resultingArray = oldArray.filter((currentValue, index, oldArr) => {
  // return true or false
}, this);

filter expects two parameters.

  1. callback function. This does the main job. We have to return true to keep the element in resultingArray and false to exclude the element. We can use traditional function. Or ES6 arrow function. In our case, (currentValue, index, oldArr) => { // return true or false } this is the callback function.
  2. this argument. You can use it as this value in the callback function. It is optional and rarely used.

Now, callback function accepts 3 arguments. These arguments are optional. But, the first two arguments are frequently used.

  • currentValue. This is the element or value being processed in every loop iteration.
  • index. This represents the index of currentValue in the original array.
  • array. This is a rarely used argument. This represents the original array on which the filter method was applied.

After processing, filter returns a new array. In our case, that array is resultingArray. filter creates this new array without modifying oldArray. The resultingArray contains elements for which callback function returned true.

Example:

const persons = [
  { name: "Jane", age: 19 },
  { name: "John", age: 21 },
  { name: "Rick", age: 17 },
  { name: "David", age: 22 },
];

const names = persons.filter(() => true);

// ES5 function syntax:
// const names = persons.filter(function () {
//   return true;
// });

console.log(names);
// output:
// [
//   { name: 'Jane', age: 19 },
//   { name: 'John', age: 21 },
//   { name: 'Rick', age: 17 },
//   { name: 'David', age: 22 }
// ]

In this example, we have created an exact copy of the original array. In the filter method, I am passing a function that returns true in every iteration. As it returns true for every element in the original array, every element is present in the new array. If we return false for every element, then the new array would be empty.

If we wanted an array which will only contain those elements where person is more than 20 years old, then we could do the following:

const persons = [
  { name: "Jane", age: 19 },
  { name: "John", age: 21 },
  { name: "Rick", age: 17 },
  { name: "David", age: 22 },
];

const newPersons = persons.filter((person) => {
  return person.age > 20;
});

// ES5 function syntax:
// const newPersons = persons.filter(function (person) {
//   return person.age > 20;
// });

console.log(newPersons);

/* output: [ { name: 'John', age: 21 }, { name: 'David', age: 22 } ]

In this example, we have created a new array containing persons who are more than 20 years old. In the filter method, I am passing a function which takes a person and returns true if that person's age is more than 20 and otherwise returns false. So, the filter method will iterate the persons' array. When we return true, the element in that iteration will be in the new array and when we return false, the element in that iteration will not be in the new array.

Now in the first example, I used shorthand syntax to return true and in the second example, I returned true and false explicitly.

We can use normal callback function instead of ES6 arrow function. But, arrow functions are more readable.

I will now share another example with index and array in callback function:

const persons = [
  { name: "Jane", age: 19 },
  { name: "John", age: 21 },
  { name: "Rick", age: 17 },
  { name: "David", age: 22 },
];

const newPersons = persons.filter(
  (person, index, array) => person.age > 20 && index < array.length / 2
);

// ES5 function syntax:
// const newPersons = persons.filter(function (person, index, array) {
//   return person.age > 20 && index < array.length / 2;
// });

console.log(newPersons);

// Output: [ { name: 'John', age: 21 } ]

In this example, I am creating a new array with only persons who are more than 20 years old and are in the first half of the array. So, David is not in the resulting array despite being more than 20 years old as he is in the second half of the array.

All modern browsers support filter. You can find complere reference here

When not to use the filter method

When you need to modify an array, filter will not be able to do the job in that case. filter returns the same element for which callback function returns true.

So, when you need to modify the array elements, you can use map.

You should learn about all array methods to use them appropriately in your codebase.

Why filter is more readable

Suppose, you are creating a new array of persons who are more than 20 years old like our second example with traditional for loop. Then, the code should be like this:

let newPersons = [];
for (let i = 0; i < persons.length; i++) {
  if (persons[i].age > 20) {
    newPersons.push(persons[i]);
  }
}

You need to go through the whole code to understand that I am creating a new array with persons who are more than 20 years old. You will also have to check if I have written a break or continue statement to skip any particular value or not. You will also have to check if I am modifying the elements of the array or not.

But, in my filter example, as soon as you see a filter method, you know that I am creating a new array with the same type of elements as the original array. You will be sure that in the resulting array, elements structure or type is not modified. Also, the main logic of elements which will be in the resulting array is very easy to find.

const newPersons = persons.filter((person) => {
  return person.age > 20;
});

When we use filter, we can focus more on logic cause it's purpose is defined.

Conclusion

The filter method has a specific purpose. That purpose is: creating a new array with elements that pass a specific condition. Whenever we need this functionality in our code, we should be using filter for better readability and maintainability.