filter
In the previous lesson, you learned that .map() transforms every item in an array and returns a new array of the same length.
Now you will learn how to keep only some items.
That is what .filter() is for.
If .map() means:
Transform every item.Then .filter() means:
Keep only the items that pass a condition.What Is filter?
filter is an array method that creates a new array containing only the elements that pass a test.
const numbers = [1, 2, 3, 4, 5, 6];
const evens = numbers.filter((number) => {
return number % 2 === 0;
});
console.log(evens); // [2, 4, 6]
console.log(numbers); // [1, 2, 3, 4, 5, 6]The original array is unchanged.
The new array contains only the items where the callback returned true.
You can read .filter() like this:
Look at each item.
Run a condition.
Keep the item if the condition passes.
Discard it if the condition fails.Basic Syntax
The syntax looks like this:
const newArray = originalArray.filter(function (currentValue, index, array) {
return condition;
});The callback can receive three arguments:
| Argument | Meaning | Common? |
|---|---|---|
currentValue |
The current element being processed | Yes |
index |
The index of the current element | Sometimes |
array |
The original array filter was called on |
Rarely |
The most important rule is:
Return true to keep the item.
Return false to remove the item.Technically, the callback can return any truthy or falsy value.
But when learning, it is clearest to return an explicit boolean condition.
Basic Example: Even Numbers
const numbers = [1, 2, 3, 4, 5, 6];
const evens = numbers.filter((number) => {
return number % 2 === 0;
});
console.log(evens); // [2, 4, 6]The condition is:
number % 2 === 0This checks whether the number is even.
| Number | Condition result | Kept? |
|---|---|---|
1 |
false |
No |
2 |
true |
Yes |
3 |
false |
No |
4 |
true |
Yes |
5 |
false |
No |
6 |
true |
Yes |
Concise Arrow Function Syntax
When the condition is simple, you can use a concise arrow function.
const numbers = [1, 2, 3, 4, 5, 6];
const evens = numbers.filter((number) => number % 2 === 0);
console.log(evens); // [2, 4, 6]This:
(number) => number % 2 === 0is the short version of:
(number) => {
return number % 2 === 0;
}Both are correct.
Use the longer version when the condition needs multiple lines.
Filtering Strings
You can filter strings by length, contents, or any other condition.
const names = ["Ava", "Noah", "Mira", "Li"];
const longNames = names.filter((name) => {
return name.length >= 4;
});
console.log(longNames); // ["Noah", "Mira"]Another example:
const words = ["apple", "banana", "apricot", "cherry"];
const wordsStartingWithA = words.filter((word) => {
return word.startsWith("a");
});
console.log(wordsStartingWithA); // ["apple", "apricot"]Filtering Objects by Property
Filtering arrays of objects is one of the most common real-world uses of filter.
const products = [
{ name: "Laptop", price: 999, inStock: true },
{ name: "Mouse", price: 25, inStock: false },
{ name: "Keyboard", price: 75, inStock: true },
];
const availableProducts = products.filter((product) => {
return product.inStock === true;
});
console.log(availableProducts);Output:
[
{ name: "Laptop", price: 999, inStock: true },
{ name: "Keyboard", price: 75, inStock: true }
]Because product.inStock is already a boolean, you can write:
const availableProducts = products.filter((product) => product.inStock);This keeps products where product.inStock is truthy.
Filtering by Multiple Conditions
You can combine conditions with logical operators.
const products = [
{ name: "Laptop", price: 999, inStock: true },
{ name: "Mouse", price: 25, inStock: false },
{ name: "Keyboard", price: 75, inStock: true },
{ name: "Monitor", price: 250, inStock: true },
];
const affordableAvailableProducts = products.filter((product) => {
return product.inStock && product.price < 300;
});
console.log(affordableAvailableProducts);This keeps products that are:
- in stock
- cheaper than
300
Output:
[
{ name: "Keyboard", price: 75, inStock: true },
{ name: "Monitor", price: 250, inStock: true }
]Filtering by Index
The second callback argument is the index.
const letters = ["a", "b", "c", "d", "e"];
const evenIndexLetters = letters.filter((letter, index) => {
return index % 2 === 0;
});
console.log(evenIndexLetters); // ["a", "c", "e"]The values at indexes 0, 2, and 4 are kept.
You do not need the first argument in this example, but it is still passed by JavaScript.
Some developers write _ when they do not use a parameter:
const evenIndexLetters = letters.filter((_, index) => index % 2 === 0);The _ is just a normal parameter name.
It signals that the value is intentionally unused.
Removing Falsy Values
Because filter uses truthy and falsy results, you can remove falsy values.
const messyArray = ["Apple", null, "Banana", undefined, "", "Cherry", 0];
const cleanArray = messyArray.filter((item) => item);
console.log(cleanArray); // ["Apple", "Banana", "Cherry"]This works because the callback returns each item itself.
Truthy values are kept.
Falsy values are removed.
The removed falsy values include:
nullundefined""0
Be Careful Removing Falsy Values
Filtering with (item) => item can be useful, but it can also remove values you meant to keep.
const scores = [0, 10, 20, null, 30];
const cleaned = scores.filter((score) => score);
console.log(cleaned); // [10, 20, 30]The score 0 was removed.
If 0 is a valid value, this is a bug.
Be more specific:
const cleaned = scores.filter((score) => score !== null);
console.log(cleaned); // [0, 10, 20, 30]Or remove both null and undefined:
const cleaned = scores.filter((score) => score != null);
console.log(cleaned); // [0, 10, 20, 30]This uses the intentional value == null pattern you learned earlier.
It matches both null and undefined.
Removing Specific Values
You can use filter to remove a specific item.
const users = ["Alice", "Bob", "Charlie"];
const withoutBob = users.filter((user) => {
return user !== "Bob";
});
console.log(withoutBob); // ["Alice", "Charlie"]This is common when removing an item from a list without mutating the original array.
For example:
const tasks = [
{ id: 1, text: "Learn arrays" },
{ id: 2, text: "Practice filter" },
{ id: 3, text: "Review map" },
];
const remainingTasks = tasks.filter((task) => {
return task.id !== 2;
});
console.log(remainingTasks);The task with id: 2 is removed from the new array.
The original tasks array is not changed.
filter Does Not Mutate the Original Array
Like map, filter returns a new array.
It does not change the original array by itself.
const numbers = [1, 2, 3, 4];
const greaterThanTwo = numbers.filter((number) => {
return number > 2;
});
console.log(greaterThanTwo); // [3, 4]
console.log(numbers); // [1, 2, 3, 4]This makes filter useful when you want to create a smaller array safely.
filter Can Return an Empty Array
If no items pass the condition, filter returns an empty array.
const numbers = [1, 2, 3];
const largeNumbers = numbers.filter((number) => {
return number > 100;
});
console.log(largeNumbers); // []This is not an error.
It means no elements matched.
filter Keeps Original Elements
filter does not transform items.
It keeps or removes the original elements.
const numbers = [1, 2, 3];
const result = numbers.filter((number) => {
return number * 2;
});
console.log(result); // [1, 2, 3]Why does this keep everything?
The callback returns:
246
All of those are truthy.
So every item is kept.
If you want doubled values, use map:
const doubled = numbers.map((number) => number * 2);
console.log(doubled); // [2, 4, 6]If you want only numbers greater than 1, use a boolean condition:
const greaterThanOne = numbers.filter((number) => number > 1);
console.log(greaterThanOne); // [2, 3]Chaining filter and map
Because filter and map both return new arrays, you can chain them.
const users = [
{ name: "Alice", age: 25, role: "admin" },
{ name: "Bob", age: 17, role: "user" },
{ name: "Charlie", age: 30, role: "user" },
];
const adultUserNames = users
.filter((user) => {
return user.age >= 18;
})
.map((user) => {
return user.name;
});
console.log(adultUserNames); // ["Alice", "Charlie"]Step by step:
filterkeeps only adult users.maptransforms those users into their names.
With concise arrows:
const adultUserNames = users
.filter((user) => user.age >= 18)
.map((user) => user.name);This reads like a data pipeline.
filter vs map
Use filter to keep or remove items.
Use map to transform items.
| Feature | filter |
map |
|---|---|---|
| Main purpose | Select matching items | Transform every item |
| Callback returns | Boolean or truthy/falsy value | New value |
| New array length | Same or shorter | Always same length |
| Changes values? | No, keeps original elements | Yes, returns transformed values |
Example with filter:
const numbers = [1, 2, 3];
const greaterThanOne = numbers.filter((number) => number > 1);
console.log(greaterThanOne); // [2, 3]Example with map:
const doubled = numbers.map((number) => number * 2);
console.log(doubled); // [2, 4, 6]filter vs find
You will learn find later in this module.
For now, know this:
filterreturns all matching items in an arrayfindreturns the first matching item
const users = [
{ id: 1, name: "Alice" },
{ id: 2, name: "Bob" },
{ id: 3, name: "Charlie" },
];
const matchingUsers = users.filter((user) => user.id > 1);
console.log(matchingUsers);This returns an array:
[
{ id: 2, name: "Bob" },
{ id: 3, name: "Charlie" }
]If you only need one item, find may be better.
Best Practices
Use filter when you want a subset:
const activeUsers = users.filter((user) => user.isActive);Return clear boolean conditions:
const expensiveProducts = products.filter((product) => product.price > 100);Be careful with truthy/falsy filtering:
const cleaned = values.filter((value) => value != null);Chain filter and map when it improves readability:
const activeUserNames = users
.filter((user) => user.isActive)
.map((user) => user.name);Use filter to remove items immutably:
const remainingTasks = tasks.filter((task) => task.id !== completedTaskId);Common Mistakes
Mistake 1: Returning the Item Instead of a Condition
const numbers = [1, 2, 3];
const result = numbers.filter((number) => number);
console.log(result); // [1, 2, 3]This keeps all numbers because they are all truthy.
If you want numbers greater than 1, write the condition:
const result = numbers.filter((number) => number > 1);
console.log(result); // [2, 3]Mistake 2: Forgetting return
const numbers = [1, 2, 3];
const result = numbers.filter((number) => {
number > 1;
});
console.log(result); // []With braces, arrow functions need an explicit return.
Correct:
const result = numbers.filter((number) => {
return number > 1;
});Or:
const result = numbers.filter((number) => number > 1);Mistake 3: Expecting filter to Transform Values
const numbers = [1, 2, 3];
const result = numbers.filter((number) => number * 2);
console.log(result); // [1, 2, 3]filter keeps or removes original items.
It does not transform them.
Use map for transformations:
const result = numbers.map((number) => number * 2);
console.log(result); // [2, 4, 6]Mistake 4: Accidentally Removing Valid Falsy Values
const scores = [0, 10, 20, null];
const cleaned = scores.filter((score) => score);
console.log(cleaned); // [10, 20]The valid score 0 was removed.
Be specific:
const cleaned = scores.filter((score) => score !== null);
console.log(cleaned); // [0, 10, 20]Quick Check
What does this return?
const numbers = [1, 2, 3, 4];
const result = numbers.filter((number) => number > 2);It returns:
[3, 4]What does this return?
const numbers = [1, 2, 3];
const result = numbers.filter((number) => {
number > 1;
});It returns:
[]The callback does not return the condition.
What should you use if you want [2, 4, 6] from [1, 2, 3]?
Use map, not filter:
const doubled = numbers.map((number) => number * 2);Summary
filter creates a new array containing only the items that pass a condition.
- Use
filterwhen you want a subset of an array. - The original array is not changed.
- Return
trueor a truthy value to keep an item. - Return
falseor a falsy value to remove an item. filtercan return an empty array.filterkeeps original items; it does not transform them.- Use
mapfor transformations. - Chain
filterandmapwhen you need to select and transform data. - Be careful with truthy/falsy filtering when values like
0or""are valid.