Menu

JavaScript Array Methods: map, filter, reduce, and Friends

The array methods that replace most of your for loops — map, filter, reduce, find, some, every — and which ones mutate versus return a new array.

Arrays Come with a Toolbox

JavaScript arrays carry a large set of built-in methods. Most of what you'd write a for loop for — transforming values, picking some out, summing them up — has a method that does it in one line, reads better, and composes cleanly with others.

The starter kit is three methods: map, filter, and reduce. Learn those and a handful of their cousins, and your loop-heavy code collapses into something you can scan at a glance.

index.js
Output
Click Run to see the output here.

Each method takes a callback and returns something. None of them modified nums — that's a theme worth internalizing early.

map: Transform Every Element

map takes a function and calls it on each element, collecting the return values into a new array of the same length. Use it when you want "one output per input."

index.js
Output
Click Run to see the output here.

The callback also receives the index as a second argument if you need it: arr.map((item, i) => ...). Ignore it when you don't.

One common mistake: reaching for map when you don't need the returned array. If you just want to print each item or push to a database, that's a forEach or a plain loop.

filter: Keep the Ones That Match

filter calls a predicate — a function that returns true or false — on each element and keeps the ones that return truthy. The new array is the same length or shorter.

index.js
Output
Click Run to see the output here.

map and filter chain naturally. Read the chain left to right as a pipeline:

index.js
Output
Click Run to see the output here.

Filter first, then map — that way map only runs over the survivors.

reduce: Fold an Array Down to One Value

reduce is the most general of the three. You give it a reducer function (accumulator, item) => newAccumulator and a starting value. It walks the array, feeding each item to the reducer along with the accumulator so far, and returns whatever the accumulator ended up as.

index.js
Output
Click Run to see the output here.

The result doesn't have to be a number. It can be an object, another array, a string — anything you build up:

index.js
Output
Click Run to see the output here.

Always pass the initial value (the second argument). Without it, reduce uses the first element as the starting accumulator, which breaks on empty arrays and often doesn't do what you want anyway.

reduce is powerful but can be hard to read when the logic gets tangled. If your reducer is more than a few lines, a plain for...of loop is often clearer.

forEach: Side Effects, No Return

forEach is like map without the returned array. It exists for when you want to do something with each item — log it, call an API, update the DOM — and don't need a new collection.

index.js
Output
Click Run to see the output here.

Two things to know:

  • forEach returns undefined. You can't chain .map() after it.
  • You can't break out of a forEach early. If you need early exit, use for...of or some/every.

If you catch yourself writing arr.forEach(x => results.push(transform(x))), that's a map.

find and findIndex: Just One, Please

find returns the first element that matches a predicate, or undefined if nothing matches. findIndex returns the index (or -1).

index.js
Output
Click Run to see the output here.

find stops at the first match. Don't use filter(...)[0] — it scans the whole array just to throw the rest away.

some and every: Boolean Questions

some returns true if at least one element passes the test. every returns true only if all of them do.

index.js
Output
Click Run to see the output here.

Both short-circuit — some stops on the first true, every stops on the first false. They're the right tool for "does any…" / "do all…" questions.

slice vs splice: Copy vs Cut

These two sound similar and do very different things.

slice(start, end) returns a shallow copy of part of the array. It doesn't modify anything. end is exclusive; omit it to go to the end.

index.js
Output
Click Run to see the output here.

splice(start, deleteCount, ...items) mutates the array in place. It removes deleteCount elements starting at start, optionally inserts new ones, and returns the removed elements.

index.js
Output
Click Run to see the output here.

Mnemonic: slice is safe (copies), splice surgically edits the array in place.

Mutating vs Non-Mutating

This distinction matters. Code that accidentally mutates a shared array is one of the more annoying bugs to track down.

Mutating (modify the original, usually return something else):

  • push, pop, shift, unshift
  • splice, sort, reverse
  • fill, copyWithin

Non-mutating (return a new array or value, original untouched):

  • map, filter, slice, concat
  • flat, flatMap
  • find, findIndex, some, every, includes, indexOf
  • reduce, reduceRight

The two to watch are sort and reverse — they look innocent and quietly mutate. If you need a sorted copy, slice first:

index.js
Output
Click Run to see the output here.

Modern JS also has non-mutating twins: toSorted, toReversed, toSpliced, and with. They return new arrays and leave the original alone. Supported in every current runtime — use them when you have them.

index.js
Output
Click Run to see the output here.

flat and flatMap

flat flattens nested arrays by one level (or more, with a depth argument). flatMap is map followed by a one-level flat — useful when each item maps to zero or more outputs.

index.js
Output
Click Run to see the output here.

flatMap is the clean way to "expand" items — one input, many outputs — without an extra flat() step.

Putting It Together

A small realistic example. Given a list of orders, get the total revenue for completed orders over $50:

index.js
Output
Click Run to see the output here.

Three methods, one pipeline, no loop bookkeeping. Each step describes what it does. You could fuse the two filter calls, but splitting them reads fine and sometimes helps when you're debugging.

Next: Map and Set

Arrays handle ordered sequences well, but they're clumsy when you need fast lookups by key or a collection of unique values. JavaScript has two built-in data structures for exactly those jobs — Map and Set — and they're the next page.

Frequently Asked Questions

What's the difference between map, filter, and reduce in JavaScript?

map transforms each element and returns a new array of the same length. filter keeps only the elements that pass a test and returns a (usually shorter) new array. reduce walks the array and folds it down to a single value — a sum, an object, another array, whatever you build up.

What's the difference between forEach and map?

forEach runs a function for each element and returns undefined — it's for side effects. map runs a function for each element and returns a new array of the results. If you want a transformed array, use map. If you just want to do something per element and don't need the result, use forEach (or a for...of loop).

Which array methods mutate the original array?

The mutating ones are push, pop, shift, unshift, splice, sort, reverse, fill, and copyWithin. Everything else — map, filter, slice, concat, flat, flatMap, find, some, every, reduce — leaves the original array alone and returns a new value.

When should I use slice vs splice?

slice(start, end) returns a shallow copy of a section of the array and doesn't touch the original. splice(start, deleteCount, ...items) mutates the array — it removes and/or inserts elements in place and returns the removed ones. Mnemonic: slice is safe, splice surgically edits.

Learn to code with Coddy

GET STARTED