Reference

Reference · Arrays

Array.prototype.filter()

filter() builds a new array containing only the elements that pass a test you provide. The original array is left unchanged.

XCODXReference · Updated

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

ParameterRequiredDescription
callbackFnYesPredicate run for each element. Return a truthy value to keep the element, falsy to drop it.
elementThe current element being tested.
indexThe index of the current element.
arrayThe array filter() was called on. (It is *not* the new array being built.)
thisArgNoValue 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?
No. 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?
Anything truthy to keep the element, anything falsy to drop it. Returning nothing (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?
Chain 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?
An 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.