Array.prototype.filter()
filter() builds a new array containing only the elements that pass a test you provide. The original array is left unchanged.
Definition
Array.prototype.filter() creates a new array containing only the elements of the original for which your callback returns a truthy value. It's how you *select* a subset of a list — the active users, the numbers above a threshold, the non-empty strings — without touching the original array.
Your callback is a predicate: a function that returns true to keep an element or false to drop it. Any truthy value keeps the element; any falsy value (false, 0, '', null, undefined, NaN) drops it.
Syntax
array.filter(callbackFn)
array.filter(callbackFn, thisArg)
array.filter((element, index, array) => {
return /* true to keep this element, false to drop it */;
})
Parameters
| Parameter | Required | Description |
|---|---|---|
callbackFn | Yes | Predicate run for each element. Return a truthy value to keep the element, falsy to drop it. |
element | — | The current element being tested. |
index | — | The index of the current element. |
array | — | The array filter() was called on. (It is *not* the new array being built.) |
thisArg | No | Value to use as this inside callbackFn. |
Return value
A new array containing a shallow copy of every element for which callbackFn returned a truthy value. If no element passes, an empty array is returned.
- The original array is not modified.
- The result is dense: in a sparse array, empty slots are skipped and never appear in the output.
- Order is preserved — kept elements stay in their original order.
Examples
Keep elements that pass a test
Filter a list of objects
const users = [
{ name: 'Ada', active: true },
{ name: 'Linus', active: false },
{ name: 'Grace', active: true },
];
const activeNames = users.filter(u => u.active).map(u => u.name);
console.log(activeNames); // ['Ada', 'Grace']
Remove all falsy values
Passing the Boolean constructor as the predicate drops every falsy element — a clean way to strip null, undefined, 0, '' and NaN in one step.
const messy = ['a', '', 0, 'b', null, undefined, 'c', NaN];
const clean = messy.filter(Boolean);
console.log(clean); // ['a', 'b', 'c']
Search / text matching
const names = ['Ada', 'Bob', 'Cara'];
const matches = names.filter(n => n.toLowerCase().includes('a'));
console.log(matches); // ['Ada', 'Cara']
Remove duplicates
A well-known idiom keeps an element only the first time it appears. For primitives, a Set is simpler and faster — but the filter() version is worth understanding:
const nums = [1, 2, 2, 3, 3, 3];
// filter idiom: keep the first occurrence of each value
const unique = nums.filter((value, index, arr) => arr.indexOf(value) === index);
console.log(unique); // [1, 2, 3]
// simpler for primitives
console.log([...new Set(nums)]); // [1, 2, 3]
Browser & runtime support
The async-callback trap
filter() is synchronous. If you pass an async function, it returns a Promise for every element — and a Promise object is always truthy — so nothing gets filtered out.
// ❌ does NOT work — every element is kept
const kept = [1, 2, 3].filter(async n => n > 2); // [1, 2, 3]
// ✅ resolve the async work first, then filter synchronously
const checks = await Promise.all([1, 2, 3].map(async n => (await isAllowed(n))));
const allowed = [1, 2, 3].filter((_, i) => checks[i]);
Availability
filter() has been part of the language since ECMAScript 5 (2009) and works in every modern browser and every maintained version of Node.js.
Frequently asked questions
Does filter() change the original array?
filter() returns a new array and leaves the original unchanged. It makes a shallow copy — the kept elements are the same object references, not clones.What does the callback need to return?
undefined) counts as falsy, so a callback that forgets to return will drop every element.How do I filter and transform at the same time?
filter() then map(), or use reduce() to do both in a single pass. filter() alone can only include or exclude elements, not change them.Why does filter() with an async callback keep everything?
async function always returns a Promise, and every Promise is truthy, so every element passes the test. Resolve your async checks first (e.g. with Promise.all), then filter synchronously against the results.