Array filter creates a new array. It does this by calling a function that you provide as the first argument with each item in the source array. Then it looks at the return value from that function call.
If it's a truth-y value, such as a number, a string, or true, then the current item we're looking at will make it into the filtered array. However, if the function call returns a false-y value, then the item is discarded.
In this example, our source array has five items in it. We call filter on it. We provide function as the first argument.
This function will be called once for each item. X will be equal to the current item that we're looking at, and we return the result of this expression.
On the first call, x will be equal to one. This will return false, so this item is discarded. When it's called with two, false again. Three, false again.
But finally, four and five will yield a true value from this expression so that those two items will make it into the filtered array. That's why when we log this to the console, you can just see a new array that contains the items four and five.
Note that this is actually a new array. If we log items to the console just above it, you can see that the original is untouched, but we have our filtered array below.
Now let's look at some of the various ways you can use filter. Here we have an array of objects. They represent people. They have a name property and a pets property.
If you wanted to create a new array that only contained those people that had pets, you could call filter on the people array, provide a function that checked the length of that pet's array.
We log that to the console. You can see we only get Shane and Simon. We don't get this person.
Remember that you only need to return a truth-y or false-y value to the function that gets called for each item. Because calling length on an empty array will return the number zero, this is a false-y value. That's why this works.
If the data you were working with instead omitted the pets property if a person didn't have any pets, how could we filter that? This wouldn't work because we're calling length on a property that may or may not exist. If we run this, you can see we get an error.
Again, we can leverage the fact that we don't need to return a strict true or false to the filter method. We could simply say x.pets. If the pets property does not exist here, this expression will return undefined, which is absolutely fine for the filter method. It will simply exclude the item, which is what we wanted in the first place. If we run that again, you can see it works.
As with most array methods, the real power comes when you begin chaining methods together. Here we have an array of lessons. Each item has a title, a view count, and an array of text. We have three items in the array category. Then we have one item in the bottom that's in the functions category.
Let's mimic a simple search functionality. We want to filter these lessons based on a tag that was given. We'll also filter for popular videos. We'll use 1,000 as the baseline. We want a new array that only contains items that are in the array category with a view count over 1,000.
How to go about this, first, let's set up the variables. We'll say that the min views needs to be 1,000. The search term is array. Then we can set up our new filtered variable which is the result of calling lessons filter.
The first thing we want to do is remove anything that's not in the array category. We can do that by simply saying, "x.tags index of search term greater than -1." This is the expression that we return. For the first three items, it will be true as the word array exists in each of these.
Then we can filter again. This time, we only want items that have a view count that's greater than our min views variable, which is 1,000. This will exclude this first one.
We want to change the order of the results so that the most popular is first. We can call sort, provide a comparative function. We want them to be in descending order. We can say, "b.views - a.views."
Following this, we can call map, provide a template stream, and put a bit of HTML in here. We can use the title property. Then finally, join it together with a new line character.
Then we can log to the console another template stream. If we run this, you can see that we just have two list items here that are sorted based on which had the most views.
To recap, we start with an array of objects like this. We first filter out any items that do not contain our search term in the tags array by calling index of and checking its value is greater than -1, which means it does exist in the array.
We call filter again. We check that the view count is more than the min views variable that we set. Then we sort the results using a numeric sort.
At this point, we just have the array of two items. We call map on that, which returns a string of HTML. Then we join them together with a new line character. This is just for display purposes here. Finally, we log to the console and pass our filtered result.
It's worth noting here we call filter twice. Technically, you could provide a regular function here and do both checks inside the single function call. You would absolutely want to do this if you have thousands or millions of items to iterate over.
However, for small collections of data, you're not going to see a difference in performance. If it's more readable to you, by all means, call filter more than once.