JavaScript: Learn to filter array
Tags: javascript, webdev
Published: 2020-05-18 11:59:38

In my <a href="https://blog.iamsabir.com/javascript-array-map-method/" title="forEach" target="_blank">previous blog</a> 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:
```jsx
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:
```jsx
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:

```jsx
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:

```jsx
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 <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter#Browser_compatibility" title="filter browser compatibility" target="_blank" rel="noopener noreferrer">here</a>

## 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 <a href="https://blog.iamsabir.com/javascript-array-map-method/" title="map" target="_blank">`map`</a>.

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:

```jsx
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.

```jsx
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.