Array.prototype.filter()

The counterpart to map: map changes each element and keeps the length, filter keeps each element and changes the length. Reaching for the wrong one is the commonest Array mix-up.

Array methodES5 (2009)Live demo
Common call
items.filter(x => x > 0)
Returns
a new array, same elements, possibly fewer
Replaces
a for loop with an if and a push
Watch out
the callback is tested for TRUTHINESS, not for `=== true`
array.filter(callback[, thisArg])
→ Array

Demo

Live evaluation
Try:
Inputs
itemsnumber[]numbers, comma separated
thresholdnumberkeep values above this
Output
[1, 2, 3, 4].filter(x => x > 2)
[3, 4]

Only the elements that satisfy the test survive, so the output is usually shorter than the input — that is the whole difference from map. When nothing passes you get an empty array rather than null or undefined, which means you can always safely chain another array method onto the result.

Parameters

NameTypeRequiredDescription
callbackFunctionyesCalled as callback(element, index, array). The element is kept when the return value is truthy.
thisArganyno (undefined)Value of `this` inside the callback. Ignored for arrow functions.

Return value

Array — A NEW array holding only the elements for which the callback returned a truthy value. The original array is never modified.

Common patterns

Drop empty or falsy values
Boolean as the callback removes every falsy element in one go.
const clean = values.filter(Boolean);
Filter then transform
Narrow first so map does less work.
const names = users.filter(u => u.active).map(u => u.name);
Remove one item by id
The non-mutating alternative to splice.
const rest = items.filter(i => i.id !== targetId);

Examples

1. Keep the big ones
[1, 2, 3, 4].filter(x => x > 2)
Returns
[3, 4]
2. Nothing passes
[1, 2, 3].filter(x => x > 99)
Returns
[]
3. Empty in, empty out
[].filter(x => x > 1)
Returns
[]
4. Drop falsy values
[0, 1, '', 'a'].filter(Boolean)
Returns
[1, 'a']
5. Missing return
[1, 2, 3].filter(x => { x > 1 })
Returns
[]
6. Original untouched
const a = [1, 2, 3]; a.filter(x => x > 2); a
Returns
[1, 2, 3]

Pitfalls

1. A braced callback with no return drops everything
Without an explicit return the callback yields undefined, which is falsy, so every element fails the test. You get an empty array rather than an error — and an empty array looks like a legitimate result.
No return
[1, 2, 3].filter(x => { x > 1 })
[]
Return it
[1, 2, 3].filter(x => x > 1)
[2, 3]
2. It tests truthiness, not equality with true
Any truthy value keeps the element, so a callback returning a string or a number works — usually helpfully, occasionally not. Returning 0 or an empty string silently drops the element.
Falsy but meaningful
[{n: 0}, {n: 1}].filter(o => o.n)
[{ n: 1 }] // the zero is gone
Be explicit
[{n: 0}, {n: 1}].filter(o => o.n !== undefined)
both kept
3. filter cannot transform
The elements come through unchanged — only which ones survive can differ. Returning a modified value from the callback changes nothing except whether the ORIGINAL element is kept.
Transform ignored
[1, 2].filter(x => x * 10)
[1, 2] // not [10, 20]
Use map
[1, 2].map(x => x * 10)
[10, 20]
4. Filtering for one item still gives an array
Even a unique match comes back wrapped. Using the result directly where an object is expected quietly passes an array instead.
Array, not object
users.filter(u => u.id === 1)
[{...}]
Use find
users.find(u => u.id === 1)
{...} or undefined

When to use

Use it
  • Narrowing an array to the elements that matter
  • Removing falsy values with filter(Boolean)
  • Non-mutating removal, as an alternative to splice
Reach for something else
  • You want to change each element → map
  • You want exactly one match → find
  • You only need to know whether any match → some
  • You are reducing to a single value → reduce

Notes

Complexity
O(n) — the callback runs once per element
Return
A new array; the original is never modified
CPython impl
V8: Builtins-array-filter.tq — fast path for packed arrays
Memory
Allocates a new array sized to the number of matches
Thread-safe
Single-threaded; mutating the source inside the callback is undefined behaviour for unvisited indices

FAQ

Almost always because the callback returns nothing. An arrow function with braces needs an explicit return — without it every element yields undefined, which is falsy, so nothing survives.

[1, 2, 3].filter(x => { x > 1 })   // []
[1, 2, 3].filter(x => x > 1)       // [2, 3]

History

ES5
Array.prototype.filter standardised in 2009, having shipped in JavaScript 1.6 (2005).