Array methods: map, filter, reduce

JavaScript · Practical · 15 min

These methods are the idiomatic way to process data in JavaScript and appear in nearly every codebase.

Arrays have methods that take a callback and do the looping for you. The callback receives (element, index, array).

Transforming and selecting — these return a new array:

  • map(fn) — one output per input: users.map(u => u.name).
  • filter(fn) — keep elements where fn returns truthy.
  • flatMap(fn) — map, then flatten one level; handy when each input yields 0..n outputs.

Searching:

  • find(fn) / findLast(fn) — the first/last matching element, or undefined.
  • findIndex(fn) — its index, or -1.
  • some(fn) / every(fn) — booleans; they stop as soon as the answer is known.

Combining: reduce((acc, x) => ..., initial) folds the array into one value — a sum, an object, a lookup table. Always pass the initial value; without it, an empty array throws.

forEach(fn) just runs the callback; use it (or for...of) for side effects. It ignores return values and you can't break out of it.

Sorting has two traps. sort() mutates the array, and with no comparator it compares elements as strings, so [10, 9, 1].sort() gives [1, 10, 9]. Pass a comparator — (a, b) => a - b for numbers, (a, b) => a.name.localeCompare(b.name) for text — and use toSorted() (ES2023) when you want a sorted copy.

Object.groupBy(items, fn) (ES2024) groups elements into an object keyed by the callback's result.

Chain methods to build readable pipelines, but remember each step creates a new array; for huge datasets a single loop may be faster.

Example

const orders = [
  { id: 1, customer: "ada", total: 120, status: "paid" },
  { id: 2, customer: "bob", total: 35, status: "open" },
  { id: 3, customer: "ada", total: 80, status: "paid" },
];

const paidTotals = orders
  .filter(o => o.status === "paid")
  .map(o => o.total);
console.log(paidTotals);                         // [ 120, 80 ]

const revenue = orders.reduce((sum, o) => sum + o.total, 0);
console.log(revenue);                            // 235

console.log(orders.find(o => o.total < 50)?.id); // 2
console.log(orders.some(o => o.status === "open")); // true

const byTotal = orders.toSorted((a, b) => b.total - a.total);
console.log(byTotal.map(o => o.id));             // [ 1, 3, 2 ]

const byCustomer = Object.groupBy(orders, o => o.customer);
console.log(Object.keys(byCustomer));            // [ 'ada', 'bob' ]

console.log([10, 9, 1].sort());                  // [ 1, 10, 9 ]  (string order!)

Remember

  • map/filter/flatMap return new arrays; find/some/every search
  • reduce folds to one value — always pass an initial value
  • sort mutates and compares as strings by default; pass a comparator or use toSorted

Watch out for

  • Using map just to loop (ignoring the result) — use forEach or for...of.
  • Calling sort() on numbers without a comparator.

Check yourself

  1. What does [10, 9, 1].sort() return?
  2. Which method stops iterating at the first element that satisfies the callback and returns true?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Indexed_collections