# Javascript Array Filter Method

The filter method in Javascript creates a shallow copy of an array, filtering it based on a number of conditions. It accepts a callback function. The array which `filter` produces will usually be a reduced version of the original array. Here is a basic example:

```javascript
let myArray = [ '⚡️', '🔎', '🔑', '🔩' ];
let filteredArray = myArray.filter((element) => {
    return (element == '🔑' || element == '🔩'))
});

console.log(filteredArray); // [ '🔑', '🔩' ]
```

As you can see, the filter method will allow an element to be in the new, filtered array, should that element return `true`. It effectively loops through each element, and runs a test on it, to see what should be left. Since arrow functions return true implicitly on a single line, you might see a more reduced version of this code written like this:

```javascript
let myArray = [ '⚡️', '🔎', '🔑', '🔩' ];
let filteredArray = myArray.filter(element => element == '🔑' || element == '🔩');

console.log(filteredArray); // [ '🔑', '🔩' ]
```

## The filter method callback function
As mentioned, `filter` accepts a callback function. The callback function consists of 3 arguments:
```javascript
Array.filter((element, index, array) => {
    // Filter the array
});
```

Let's look at what each of these do

### element
This is the current element being examined by `filter`. `filter` goes through each item in the array to test if it should exist in the new, filtered array.

### index
This is the zero based index of the array item we are working with. For example, if we were viewing the first element in the array, this would be `0`.

### array
This is the entire array, should you wish to do something with the original array.

## Mutating arrays within the filter method
Since filter uses a callback function, it is possible to mutate the original array we are examining. For example, we could push new items to the array each time we filter over an item:
```javascript
let myArray = [ '⚡️', '🔎', '🔑', '🔩' ];
let filteredArray = myArray.filter((element) => {
    myArray.push('⚡️');
    return true;
});

console.log(filteredArray); // [ '⚡️', '🔎', '🔑', '🔩' ]
```

As you might have already realised, this would produce an infinite loop. Fortunately, much like in [reduce](https://fjolt.com/article/javascript-reduce), Javascript does not allow this to happen - instead, any new elements to an array added in this way are ignored. However, mutation of existing elements is totally fine:
```javascript
let myArray = [ '⚡️', '🔎', '🔑', '🔩' ];
let filteredArray = myArray.filter((element, index) => {
    myArray[index + 1] = '⚡️';
    return (element == '⚡️');
});

console.log(filteredArray); // [ '⚡️', '⚡️', '⚡️', '⚡️' ]
```

## Filtering Arrays of Objects 
Filtering arrays of objects follows the same conventions as with arrays. We can filter upon child properties of objects within an array by using the `.` notation. For example, if I wanted to filter the following array by `age`, where age should be >18, I would do something like this:
```javascript
let myArray = [ { age: 4 }, { age: 12 }, { age: 19 }, { age: 21 } ];
let filteredArray = myArray.filter((element, index) => {
    return (element.age > 18);
});
console.log(filteredArray); // [ { age: 19 }, { age: 21 } ]
```

## Filtering Arrays by Search Criteria
A common use for `filter` is to take an array of values, and search through them based on a search term. This can be done with `includes`, or `regex`. For example:
```javascript
let myArray = [ 'cat', 'catdog', 'dog', 'fish', 'fishcat' ]
let filteredArray = myArray.filter((element, index) => {
    return element.match(/cat/)
});
console.log(filteredArray); // ['cat', 'catdog', 'fishcat']
```

## Filter makes a Shallow Copy of Arrays
Although it may appear that `filter` makes a new copy of the original array, this is not the case. In fact, `filter` makes a **shallow copy** of the original array, which means that if we mutate objects within the array, the original will change too. To understand this, let's look at our age example again:
```javascript
let myArray = [ { age: 4 }, { age: 12 }, { age: 19 }, { age: 21 } ];
let filteredArray = myArray.filter((element, index) => {
    return (element.age > 18);
});

console.log(filteredArray); // [ { age: 19 }, { age: 21 } ]

filteredArray[0].age = 50;
filteredArray[1] = { age: 40 };

console.log(filteredArray); // [ { age: 50 }, { age: 40 } ]
console.log(myArray); // [ { age: 4 }, { age: 12 }, { age: 50 }, { age: 21 } ]
```

As you can see, modifying the filtered array using the `filteredArray[0].age` notation also modifies the original - but **wait**! `filteredArray[1] = { age: 40 }` changes only the filtered array. That's because although Javascript interprets the `.` notation as updating both arrays, it interprets the square bracket notation `[]` as setting a new value at the second position of the filtered array.

This is just another quirk of Javascript which can be confusing, but is very useful to know!

## Conclusion
The filter method is widely used and an easy way to change create new subsets of arrays based on certain criteria. It should be noted that only a shallow copy is made of the original array, so modifying the array in certain ways will affect the original. 
