jsguides

Array.prototype.filter()

filter(callbackFn, thisArg)

The filter method creates a shallow copy of a portion of a given array, filtered down to just the elements from the given array that pass the test implemented by the provided function.

Syntax

filter(callbackFn)
filter(callbackFn, thisArg)

Parameters

ParameterTypeDefaultDescription
callbackFnfunctionrequiredFunction to test each element. Return true to keep the element, false otherwise.
elementany-The current element being processed.
indexnumber-The index of the current element.
arrayArray-The array filter was called upon.
thisArganyundefinedValue to use as this when executing callbackFn.

Examples

Basic usage

const words = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present'];

const result = words.filter(word => word.length > 6);

console.log(result);
// ['exuberant', 'destruction', 'present']

Filtering with index

The callback receives the index as its second argument, which lets you filter based on position rather than value. You can use this to select every Nth element, split an array by parity, or implement a stride-based sampling pattern. For example, keeping every other element by checking if the index is even:

const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// Keep only numbers at even indices
const result = numbers.filter((num, index) => index % 2 === 0);

console.log(result);
// [1, 3, 5, 7, 9]

Filtering objects

filter() shines when working with arrays of objects. You can select objects based on any property value, making it the go-to method for querying structured data without a database. For instance, pulling all active users from a user list requires only a one-line predicate:

const users = [
  { name: 'Alice', age: 25, active: true },
  { name: 'Bob', age: 30, active: false },
  { name: 'Charlie', age: 28, active: true },
  { name: 'Diana', age: 22, active: false }
];

const activeUsers = users.filter(user => user.active);

console.log(activeUsers);
// [{ name: 'Alice', age: 25, active: true },
//  { name: 'Charlie', age: 28, active: true }]

Using thisArg

The optional second argument to filter() sets the this value inside the callback. This is particularly useful when the filtering logic depends on an external configuration object, though it only works with regular functions, not arrow functions (which capture this from their enclosing scope):

const nums = [1, 2, 3, 4, 5];

const multiplier = {
  threshold: 3
};

const result = nums.filter(function(num) {
  return num > this.threshold;
}, multiplier);

console.log(result);
// [4, 5]

Common Patterns

Finding unique values

Using filter() with indexOf() is a classic one-liner for deduplicating arrays. The trick: keep an element only if its first occurrence in the array matches its current position. While not the fastest approach for large datasets, it is concise and requires no extra data structures:

const items = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple'];

const unique = items.filter((item, index) => items.indexOf(item) === index);

console.log(unique);
// ['apple', 'banana', 'orange']

Filtering by multiple criteria

Combining conditions with logical operators inside the callback lets you filter on several fields at once. This is how you build faceted search, multi-field filters, and complex data queries without pulling in a library. Each condition narrows the result set further, producing a precise subset of the original data:

const products = [
  { name: 'Laptop', price: 999, inStock: true },
  { name: 'Mouse', price: 29, inStock: true },
  { name: 'Keyboard', price: 79, inStock: false },
  { name: 'Monitor', price: 299, inStock: true }
];

const affordableInStock = products.filter(p => p.inStock && p.price < 100);

console.log(affordableInStock);
// [{ name: 'Mouse', price: 29, inStock: true }]

Removing falsy values

Passing the Boolean constructor directly as the callback is a concise idiom that strips out false, 0, '', null, undefined, and NaN from an array all at once. Each element gets coerced to a boolean, and only truthy values survive. It reads as “keep the truthy values”:

const mixed = [0, 1, 'hello', '', null, undefined, true, false, 42];

const truthy = mixed.filter(Boolean);

console.log(truthy);
// [1, 'hello', true, 42]

How filter() works

filter() iterates every element in the array in ascending index order, calling the callback for each one. Elements where the callback returns a truthy value are included in the new array; elements where it returns a falsy value are excluded. The original array is never modified. If no elements pass the test, filter() returns an empty array - never undefined or null.

When filter() is the right fit

filter() is the best choice when you need to keep every matching element rather than just one. It is especially useful for cleanup, validation, and searching by condition because it makes the matching rule explicit. The downside is that it always scans the entire array, so it is not the best tool when you only need the first match or a boolean answer. In those cases, find() or some() is usually a better fit.

Performance

filter() always iterates the entire array, even if the first element fails. For large arrays where you expect few matches, there is no early exit optimization. If you need only the first match, find() short-circuits and is faster. If you need to know whether any match exists, some() short-circuits and is faster than filter().length > 0.

Sparse arrays

filter() skips holes in sparse arrays - they are not visited by the callback and are not included in the result. The result is always a dense (non-sparse) array.

const sparse = [1, , 3, , 5];
sparse.filter(x => x > 0); // [1, 3, 5] - holes dropped

filter() and index stability

The callback receives three arguments: the current element, its index in the original array, and the original array itself. The index argument always reflects the position in the source array, not the position the element will occupy in the result. If you need to filter based on position (for example, keeping only every other element), use the index argument directly rather than tracking a separate counter.

See Also