JavaScript Array Methods Cheat Sheet With Runnable Examples
Cheat sheet for JavaScript array methods: map, filter, reduce, find, some, every, sort, flat and more, each with a runnable example plus the gotchas.

JavaScript array methods are the built-in functions attached to every array for transforming, searching, sorting and reshaping its contents. The ones you'll reach for most days are map, filter, reduce, find, some, every, sort, slice, splice, flat and includes. Most take a callback that receives the current element, its index and the array itself, and they return either a new array or a single value.
The distinction that matters most is copying versus mutating. map, filter, slice, concat, flat, toSorted and toReversed return a new array and leave the original alone. push, pop, shift, unshift, splice, sort, reverse and fill change the array in place. The quick-reference table comes first, then runnable examples for each group, then the mistakes that bite people.
JavaScript array methods cheat sheet#
Use this table to pick a method. "Mutates" means the original array changes. Everything marked "No" hands you a new value and leaves the input alone.
| Goal | Method | Returns | Mutates original? |
|---|---|---|---|
| Transform every element | map(fn) |
New array, same length | No |
| Keep elements that pass a test | filter(fn) |
New array | No |
| Fold everything into one value | reduce(fn, initial) |
Whatever the accumulator is | No |
| First matching element | find(fn) |
Element or undefined |
No |
| Index of first match | findIndex(fn) |
Index or -1 |
No |
| Last match, from the end | findLast(fn), findLastIndex(fn) |
Element, or index | No |
| Does any element pass? | some(fn) |
Boolean | No |
| Do all elements pass? | every(fn) |
Boolean | No |
| Contains a value? | includes(value) |
Boolean | No |
| Index of a value | indexOf(value), lastIndexOf(value) |
Index or -1 |
No |
| Run a side effect per element | forEach(fn) |
undefined |
No |
| Sort in place | sort(compareFn) |
The same array | Yes |
| Sorted copy | toSorted(compareFn) |
New array | No |
| Reverse in place, or as a copy | reverse(), toReversed() |
Same array, or new array | Yes, then No |
| Copy a range | slice(start, end) |
New array | No |
| Insert or remove at a position | splice(start, deleteCount, ...items) |
Array of removed elements | Yes |
| Same as splice, but a copy | toSpliced(start, deleteCount, ...items) |
New array | No |
| Replace one index, as a copy | with(index, value) |
New array | No |
| Join arrays | concat(...arrays) |
New array | No |
| Flatten nested arrays | flat(depth) |
New array | No |
| Map, then flatten one level | flatMap(fn) |
New array | No |
| Add or remove at the end | push(...items), pop() |
New length, or removed element | Yes |
| Add or remove at the start | unshift(...items), shift() |
New length, or removed element | Yes |
| Fill a range with one value | fill(value, start, end) |
The same array | Yes |
| Array to string | join(separator) |
String | No |
Every method that returns a new array makes a shallow copy. Objects inside the array are shared by reference between the old and new arrays, so editing copy[0].name also changes original[0].name. The Array reference on MDN spells this out and also documents how each method treats empty slots in sparse arrays.
map, filter and reduce examples#
These three cover most data-shaping work. map produces exactly one output element per input element. filter keeps the elements whose callback returns a truthy value. reduce walks the array and folds it into a single result, which can be a number, a string, an object or another array.
The callback for map, filter and the other iterative methods is called as callbackFn(element, index, array). reduce is the odd one out. Its callback is (accumulator, currentValue, index, array), and the second argument to reduce itself is the starting accumulator.
const orders = [
{ id: 1, customer: "ana", status: "paid", items: [{ price: 12.5, qty: 2 }, { price: 3, qty: 1 }] },
{ id: 2, customer: "ben", status: "refunded", items: [{ price: 40, qty: 1 }] },
{ id: 3, customer: "ana", status: "paid", items: [{ price: 7.25, qty: 4 }] },
];
// map: one output per input, same length as the input
const totals = orders.map((o) => ({
id: o.id,
total: o.items.reduce((sum, item) => sum + item.price * item.qty, 0),
}));
console.log("totals:", totals);
// filter: keep the elements whose callback returns true
const paidIds = orders.filter((o) => o.status === "paid").map((o) => o.id);
console.log("paid ids:", paidIds);
// chain: keep paid orders, pull out their line items, sum them
const revenue = orders
.filter((o) => o.status === "paid")
.flatMap((o) => o.items)
.reduce((sum, item) => sum + item.price * item.qty, 0);
console.log("paid revenue:", revenue);
// reduce into an object: group order ids by customer
const byCustomer = orders.reduce((acc, o) => {
(acc[o.customer] ??= []).push(o.id);
return acc;
}, {});
console.log("by customer:", byCustomer);
A few things to notice. The chain of filter, then flatMap, then reduce reads top to bottom like a sentence. The grouping example seeds reduce with an empty object and returns the accumulator from every iteration. Forgetting that return is the single most common reduce bug. These same patterns are what you'll apply to JSON you've just pulled from a server, so if that's your starting point, the Fetch API examples show how to get the data into an array first.
reduce doesn't accept a thisArg, unlike the other iterative methods. If you leave out the initial value, it takes the first element as the starting accumulator and begins at the second element. That works for summing numbers and is wrong for almost everything else, so pass the initial value every time.
find, some, every and the other search methods#
The search methods answer three different questions: which element, where is it, and is there one at all.
const users = [
{ name: "Mara", age: 34, admin: false },
{ name: "Theo", age: 17, admin: false },
{ name: "Ivy", age: 29, admin: true },
];
console.log("first admin:", users.find((u) => u.admin));
console.log("nobody over 90:", users.find((u) => u.age > 90));
console.log("index of Theo:", users.findIndex((u) => u.name === "Theo"));
console.log("last non-admin:", users.findLast((u) => !u.admin)?.name);
console.log("any minors?", users.some((u) => u.age < 18));
console.log("all adults?", users.every((u) => u.age >= 18));
console.log("every on []:", [].every((u) => u.age >= 18));
console.log("some on []:", [].some((u) => u.age >= 18));
const names = users.map((u) => u.name);
console.log(names.includes("Ivy"), names.indexOf("Ivy"), names.indexOf("Zed"));
// some() stops at the first hit; count how often the callback actually ran
let calls = 0;
users.some((u) => {
calls++;
return u.age < 18;
});
console.log("callback calls:", calls, "of", users.length);
find returns the element itself and findIndex returns its position. When nothing matches you get undefined or -1, not an error, so guard before you dereference. findLast and findLastIndex do the same thing scanning from the end. some and every return booleans. All six stop as soon as the answer is known, which is why the call counter at the end comes out lower than the array length. For plain values such as strings and numbers, includes and indexOf skip the callback entirely.
Two edge cases to memorize: every returns true on an empty array and some returns false, because no element can fail or pass a test that never runs.
sort and the non-mutating alternatives#
sort is the method most likely to surprise you. It sorts in place and returns the same array, and with no comparator it compares elements as strings, so 100 lands before 25.
const nums = [10, 9, 1, 25, 100];
console.log("default sort:", [...nums].sort());
console.log("numeric:", [...nums].sort((a, b) => a - b));
console.log("descending copy:", nums.toSorted((a, b) => b - a));
console.log("original untouched:", nums);
const people = [
{ name: "Zoë", joined: 2021 },
{ name: "adam", joined: 2019 },
{ name: "Bea", joined: 2019 },
];
// sort by year, then by name; localeCompare handles case and accents
const sorted = people.toSorted(
(a, b) => a.joined - b.joined || a.name.localeCompare(b.name),
);
console.log(sorted.map((p) => `${p.joined} ${p.name}`));
// sort() mutates and returns the very same array object
const inPlace = [3, 1, 2];
const result = inPlace.sort((a, b) => a - b);
console.log("same object?", result === inPlace, inPlace);
Return a negative number from the comparator to put a first, a positive number to put b first, and 0 to leave them as they are. a - b ascends, b - a descends, and localeCompare sorts strings sensibly across case and accents. The || trick chains tie-breakers: when two years are equal the subtraction gives 0, which is falsy, so the name comparison decides.
The comparator may be called more than once for the same index, so keep it pure and cheap. If you need the original order later, sort a copy with toSorted, [...arr].sort(...) or arr.slice().sort(...). The sort documentation on MDN covers the comparator contract in detail.
The MDN Array page lists a non-mutating stand-in for every mutating method:
| Mutating method | Non-mutating alternative |
|---|---|
pop() |
slice(0, -1) |
push(v1, v2) |
concat([v1, v2]) |
reverse() |
toReversed() |
shift() |
slice(1) |
sort() |
toSorted() |
splice() |
toSpliced() |
unshift(v1, v2) |
toSpliced(0, 0, v1, v2) |
fill(), copyWithin() |
No one-method alternative; copy first with slice() or [...arr] |
slice, splice, flat and the reshaping methods#
slice and splice are easy to mix up. slice(start, end) copies a range and never touches the original. splice(start, deleteCount, ...items) removes and inserts in place and returns whatever it removed.
const list = ["a", "b", "c", "d"];
list.slice(1, 3); // copy of index 1 up to, not including, index 3
list.slice(-2); // copy of the last two elements
list.splice(1, 2); // removes "b" and "c" from list and returns them
list.splice(1, 0, "x"); // inserts "x" at index 1, removes nothing
list.toSpliced(0, 1); // like splice(0, 1), but returns a copy and leaves list alone
list.with(0, "z"); // copy of list with index 0 replaced
[1, [2, [3, [4]]]].flat(); // flattens one level
[1, [2, [3, [4]]]].flat(Infinity); // flattens completely
["a b", "c"].flatMap((s) => s.split(" ")); // map, then flatten one level
[1, 2].concat([3], [4, 5]); // new array joining all three
["x", "y"].join(", "); // the string "x, y"
flatMap is the one to remember when each input can produce zero, one or many outputs. Returning an empty array from the callback drops that element, which gives you filter and map in a single pass.
Common mistakes with array methods#
- Forgetting to return from the callback.
map((x) => { x * 2 })with braces returnsundefinedfor every element. Drop the braces or addreturn. - Using
mapfor side effects. If you throw the result away, useforEachor afor...ofloop.mapallocates a new array for nothing. - Trying to break out of
forEach. It can't stop early. Reach forsome,everyorfindwhen you need to stop, or write a plain loop. - Calling
reducewithout an initial value. On an empty array it throws aTypeError. On a non-empty array the first element becomes the accumulator, which silently breaks object-building reducers. - Expecting
sortto sort numbers. Without a comparator it compares strings. It also mutates, so usetoSortedwhen the original order still matters. - Assuming copies are deep.
slice,map,filter, spread and the rest copy one level. Nested objects are shared with the original. - Mutating the array inside the callback. The length is read once when iteration starts, so pushing inside
forEachdoesn't extend the loop, and splicing shifts later elements so some get skipped or visited twice. Build a new array instead. - Treating
findlikefilter.findreturns one element orundefined.filteralways returns an array, possibly empty, soif (filtered)is always true. - Passing
thisArgto an arrow function. Arrow functions don't have their ownthis, so the argument is ignored. Use a regular function or just close over the variable. - Relying on sparse-array behavior. Older iterative methods such as
forEach,map,filter,someandeveryskip empty slots.find,findIndex,includes,keysand thetoSortedfamily treat them asundefined. Avoid creating holes at all.
Practice questions that show up in interviews#
These come up constantly, and each one is a short exercise in choosing the right method.
- Count word frequencies with one
reduce. Seed with{}and writeacc[word] = (acc[word] ?? 0) + 1. - Remove duplicates.
[...new Set(arr)]is the one-liner. The array-methods version isarr.filter((x, i) => arr.indexOf(x) === i). Be ready to explain why the second is quadratic. - Flatten a nested array without
flat. A recursivereducethat callsconcaton arrays and pushes everything else. - Sort objects by two keys. A comparator that chains with
||, as in the sorting example above. - Reimplement
mapwithreduce. Push the callback's result onto an accumulator array. It proves you understand both methods. - Filter a palette down to accessible pairs. Given color tokens,
filteron a contrast function andsortby ratio. The math behind that function is in the color contrast checker walkthrough.
If you want more than exercises, the reduce reference on MDN has worked examples for grouping, flattening and running promises in sequence.
Quick reference checklist#
- Need a new array of the same length?
map. - Need a subset?
filter. Need one item?find. Need a yes or no?some,everyorincludes. - Need one value out of many?
reduce, and always pass the initial value. - Sorting? Pass a comparator. Prefer
toSortedunless you want the original changed. - Copying a range?
slice. Editing in place?splice. Edited copy?toSplicedorwith. - Nested arrays?
flatorflatMap. - Callback signature is
(element, index, array). Forreduceit's(accumulator, current, index, array). - All copies are shallow. Never mutate the array from inside a callback.
Quick answers
What is a JavaScript array method?
It's a function that lives on every array, such as map, filter or sort, and operates on that array's elements. Some return a new array or value and leave the original alone, while others like sort, splice and push change the array in place.
What's the difference between map, filter and reduce?
map returns a new array with one transformed element per input. filter returns a new array containing only the elements that pass a test. reduce folds the whole array into a single value, which can be a number, string, object or another array.
Does sort change the original array?
Yes. sort reorders the array in place and returns the same array object. Use toSorted, or copy first with slice or spread, when you need to keep the original order.
Where is the official JavaScript array methods reference?
The Array page on MDN Web Docs is the reference most developers use. It lists every method, its callback signature, whether it mutates, and how it handles empty slots in sparse arrays.
Which array methods come up most in interviews?
reduce is the most common, usually for counting, grouping or flattening. Expect questions on sort comparators, removing duplicates, the difference between find and filter, and reimplementing map or filter with reduce.
Did this solve it?
One tap. No account.
Sorry about that. What was missing?
from 0 readers
Saved you an hour? Send a tip.
USDC or ETH on Base, Ethereum, Arbitrum and more. Keeps the notes free and the examples running.
Network
0xc783bc5c3fa14cEC3f09A22284bC91C5AF0d59e1
On a computer? Scan the code with your phone wallet, or copy the address.
Pick the network your wallet or exchange uses. USDC works on all six; ETH on Base, Ethereum, Arbitrum and Optimism. Don't send on Tron or Solana: this address doesn't exist there. Tips are optional and unlock nothing; every guide stays free.
Discussion
Start the discussion
Next note