Keeping only the paid orders, only the files with one extension, only the active users: the move is so frequent that the language set aside a method for it, and writing a loop for the job no longer holds up.
filter keeps whatever passes a test and drops the rest, without ever touching the original array.
Definition
filter is an Array method that calls a function on each item and hands back a new array made of those the function answered true for. Its length is therefore lower than or equal to the starting one.
const orders = [
{ id: 1, paid: true, amount: 49 },
{ id: 2, paid: false, amount: 19 },
{ id: 3, paid: true, amount: 99 },
];
const paid = orders.filter((o) => o.paid);
console.log(paid.length); // 2
const large = orders.filter((o) => o.amount > 500);
console.log(large); // []That last line deserves attention: filter always hands back an array, an empty one where needed, never undefined. It can therefore be walked or measured with no check beforehand.
What the function has to return
The return does not have to be a boolean: its Truthy and falsy nature is what decides. An empty string, 0, null and undefined drop the item, everything else keeps it.
const raw = ["fr", "", null, "en", undefined, "es"];
console.log(raw.filter(Boolean)); // [ 'fr', 'en', 'es' ]Handing Boolean straight over as the test function is the established idiom for cleaning empty values out of an array. It works because Boolean ignores the second and third arguments filter passes to it.
filter, find or some
| What you are after | Method | What you receive |
|---|---|---|
| Everything that passes | filter | An array |
| The first that passes | Array.find() | The item, or undefined |
| Whether one exists | Array.some() | A boolean |
| How many pass | filter then length | A number |
The second row is the one most often missed: writing filter(...)[0] walks the whole array for a single item, where find stops at the first hit.
Frequently asked questions
Does filter change the original array?
Never. It builds a new one, holding the same objects rather than copies. Changing a property on a filtered item therefore shows up in both arrays, since it is one object referenced twice.
How do you remove an item by identifier?
By keeping all the others, with list.filter((o) => o.id !== target). That form beats splice, which changes the array in place and requires knowing the exact position.
Does chaining filter and Array.map() cost two passes?
Yes, two passes instead of one. Across a few hundred items, the readability of the chain is well worth that spending. Past several tens of thousands, a single loop or a Array.reduce() becomes defensible.