Skip to content
JavaScript js arrays 4 min read

Array.filter()

Array.prototype.filter() builds a new array containing only the elements for which a callback returns a truthy value. It is the go-to tool whenever you need a subset of an array — active users, valid records, non-empty strings — without mutating the original data. Because it returns a fresh array, filter fits naturally into functional, immutable-style pipelines alongside map and reduce.

The predicate function

filter takes a predicate: a function that receives each element and returns true (keep it) or false (drop it). The callback is invoked with three arguments — element, index, and the original array — though most predicates only use the first.

const numbers = [1, 2, 3, 4, 5, 6];

const evens = numbers.filter((n) => n % 2 === 0);
console.log(evens);
console.log(numbers); // original is untouched

Output:

[ 2, 4, 6 ]
[ 1, 2, 3, 4, 5, 6 ]

The result is always a new array. Its length is between 0 (nothing matched) and the original length (everything matched). Element order is preserved.

const users = [
  { name: "Ada", active: true },
  { name: "Linus", active: false },
  { name: "Grace", active: true },
];

const activeUsers = users.filter((user) => user.active);
console.log(activeUsers.map((u) => u.name));

Output:

[ 'Ada', 'Grace' ]

Using the index and array arguments

The extra arguments are handy for position-based logic, such as keeping every other element or de-duplicating while preserving order.

const letters = ["a", "b", "a", "c", "b", "d"];

// Keep the first occurrence of each value
const unique = letters.filter(
  (value, index, arr) => arr.indexOf(value) === index
);
console.log(unique);

Output:

[ 'a', 'b', 'c', 'd' ]

Removing falsy values

A common cleanup task is stripping out falsy entries — false, 0, "", null, undefined, and NaN. Passing the Boolean constructor as the predicate does exactly this, because each value is coerced to a boolean.

const messy = [0, "hello", "", null, 42, undefined, NaN, "world"];

const clean = messy.filter(Boolean);
console.log(clean);

Output:

[ 'hello', 42, 'world' ]

Tip: arr.filter(Boolean) is the idiomatic way to drop falsy values. It is concise, allocation-light, and instantly recognizable to other JavaScript developers.

Combining filter with map

filter and map compose beautifully. Filter first to narrow the set, then map to transform what remains. Reading the chain top to bottom describes the data flow.

const products = [
  { name: "Keyboard", price: 45, inStock: true },
  { name: "Monitor", price: 220, inStock: false },
  { name: "Mouse", price: 25, inStock: true },
  { name: "Webcam", price: 80, inStock: true },
];

const affordableInStock = products
  .filter((p) => p.inStock && p.price < 100)
  .map((p) => `${p.name}: $${p.price}`);

console.log(affordableInStock);

Output:

[ 'Keyboard: $45', 'Mouse: $25', 'Webcam: $80' ]

Order matters for performance: filtering before mapping means you transform fewer elements. If you find yourself filtering and transforming in a single pass over a huge dataset, consider reduce or flatMap to avoid the intermediate array.

Immutability

filter never modifies the source array — it reads each element and returns a brand-new array. This makes it safe in state management code (React, Redux, signals) where mutating existing arrays causes subtle bugs. To “remove” an item immutably, filter it out:

const todos = [
  { id: 1, text: "Write docs" },
  { id: 2, text: "Review PR" },
  { id: 3, text: "Deploy" },
];

const remaining = todos.filter((todo) => todo.id !== 2);
console.log(remaining.length); // 3 -> 2
console.log(todos.length);     // still 3

Output:

2
3

Note that filter performs a shallow copy. The new array holds references to the same objects, so mutating a nested object affects both arrays. Clone objects (via spread or structuredClone) if you need full isolation.

filter vs. similar methods

MethodReturnsUse when
filterNew array of all matchesYou want every matching element
findFirst matching element (or undefined)You want only one match
someBooleanYou only need to know if any element matches
everyBooleanYou need to confirm all elements match
mapNew array, same lengthYou transform rather than select

Gotcha: filter always scans the entire array. If you only need the first match, use find, which short-circuits and stops early.

Best Practices

  • Keep predicates pure — no side effects, no mutation — so the pipeline stays predictable.
  • Use arr.filter(Boolean) to remove falsy values instead of writing an explicit truthiness check.
  • Filter before map to transform fewer elements, and chain methods for readable data flow.
  • Reach for find, some, or every when you do not actually need the full subset; they short-circuit.
  • Remember filter is shallow — deep-clone elements when you need full immutability.
  • For very large arrays where you filter and transform together, prefer reduce or flatMap to skip the intermediate array.
Last updated June 1, 2026
Was this helpful?