Map, Filter, and Reduce
The three verbs that do 80% of modern JavaScript's work on arrays — and the mental shift behind them.
In the loops chapter we wrote out the "loop and accumulate"
pattern by hand: walk an array, build up a result. JavaScript
gives you three built-in methods — map, filter, and reduce —
that express these patterns more clearly. Once they click,
half the loops you would otherwise write disappear.
These three methods together are sometimes called the functional core of array processing.
The shift in mindset
A for loop says how to walk the array. The three methods say
what to produce.
| Loop says... | Higher-order method says... |
|---|---|
| Step from index 0 to length-1 | "For each element..." |
| Push into a result array | "Produce a new array of..." |
| Conditionally include | "Keep only the ones where..." |
| Accumulate a single value | "Combine all into..." |
The pattern is: describe the transformation, not the mechanics.
map: transform every element
arr.map(fn) returns a new array of the same length, where each
element is the result of fn applied to the original element.
Three things to notice:
- The original array is not modified.
- The result is always the same length.
- Each element is processed independently. The callback can't see the other elements.
If you need to skip elements, map is the wrong tool. That's
what filter is for.
filter: keep only the elements that pass a test
arr.filter(fn) returns a new array containing only the
elements for which fn returns a truthy value.
Notice the last example: Boolean is itself a function, and
filter(Boolean) removes every falsy value in one stroke. Tiny
idioms like this make functional code remarkably compact.
reduce: collapse the array into a single value
reduce is the most general of the three. It walks the array,
maintaining an "accumulator", and produces a single final value.
arr.reduce(
(accumulator, currentValue) => newAccumulator,
initialAccumulator,
);reduce is very general. Anything you can do with a manual
"start with X, walk the array, update X, return X" loop, you can
do with reduce. In fact, map and filter are themselves just
special cases of reduce.
A common piece of advice: don't reach for reduce first. It can
do anything, but its generality makes it harder to read than map
or filter. Reach for it when you genuinely need to fold the
array into a non-list result.
Composing the three
The real power of these methods is chaining. Each one returns a new array, so you can apply the next one immediately.
Read the first chain top-to-bottom. It says, in plain English: "take the orders, keep the paid ones, get each amount, add them all up." That readability — the way each step describes a small, clear transformation — is the whole point.
Other useful array methods
A few more that follow the same functional spirit:
some and every are particularly worth remembering — they often
replace a hand-rolled loop with an early return true.
Data flow visualised
A chain of .filter().map().reduce() is a small data pipeline.
Each step takes the previous output as input.
Each arrow carries a value (in this case, mostly arrays). Drawing a tiny pipeline like this on paper is a great way to plan transformations before writing code.
Performance notes (lightly)
Methods chained one after another walk the array multiple times. For small data this is fine; for arrays of millions of elements you might prefer a single hand-written loop or a streaming approach. For everyday programming, prefer the readable version — modern engines are fast, and clarity is more valuable than micro-optimisation.
A multi-file pipeline
Real-world programs build pipelines that span multiple modules: one module owns the transformations, another assembles them.
Challenge
Given an array of products, each shaped like { name, price, inStock }, write a function affordableInStock(products, maxPrice) that returns an array of names of products that are in stock AND have a price less than or equal to maxPrice, sorted alphabetically.
Use .filter, .map, and .sort() — not a hand-written for loop.
Examples:
- For
[{name:"A", price:5, inStock:true}, {name:"B", price:20, inStock:true}, {name:"C", price:3, inStock:false}]withmaxPrice=10, return["A"]. - For the same input with
maxPrice=100, return["A","B"].
Which of these is the cleanest expression of "give me a new array where each user's name is uppercased"?
A for loop that pushes into a new array
A for...of loop with manual indexing
users.map((u) => ({ ...u, name: u.name.toUpperCase() }))
A while loop that builds a new array index-by-index