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.
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."
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.
map and filter chain naturally. Read the chain left to right as a pipeline:
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.
The result doesn't have to be a number. It can be an object, another array, a string — anything you build up:
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.
Two things to know:
forEachreturnsundefined. You can't chain.map()after it.- You can't
breakout of aforEachearly. If you need early exit, usefor...oforsome/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).
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.
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.
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.
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,unshiftsplice,sort,reversefill,copyWithin
Non-mutating (return a new array or value, original untouched):
map,filter,slice,concatflat,flatMapfind,findIndex,some,every,includes,indexOfreduce,reduceRight
The two to watch are sort and reverse — they look innocent and quietly mutate. If you need a sorted copy, slice first:
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.
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.
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:
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.