Overview
JavaScript arrays carry two families of methods: those that return a new array or value (functional, non-mutating) and those that modify the array in place (mutating). Mixing the two families without awareness causes bugs in React state and other frameworks where mutation bypasses change detection. This card groups methods by behavior. All examples are vanilla JavaScript; TypeScript types are inferred correctly for all of these.
Transform methods (return new array)
None of these modify the original array.
| Method | Signature | Returns | Notes |
|---|---|---|---|
map | arr.map(fn) | New array, same length | Transform every element. |
filter | arr.filter(fn) | New array, subset | Keep elements where fn returns truthy. |
flatMap | arr.flatMap(fn) | New array | map then one level of flat. Replaces arr.map(...).flat(). |
flat | arr.flat(depth) | New array | Flatten nested arrays. Default depth is 1; Infinity fully flattens. |
slice | arr.slice(start, end) | New array | Shallow copy of a range; negative indices count from end. |
concat | arr.concat(other) | New array | Join two or more arrays; does not mutate either side. |
toSorted | arr.toSorted(fn) | New array | Non-mutating sort (ES2023). |
toReversed | arr.toReversed() | New array | Non-mutating reverse (ES2023). |
toSpliced | arr.toSpliced(start, del, ...items) | New array | Non-mutating splice (ES2023). |
with | arr.with(index, value) | New array | Non-mutating element replacement (ES2023). |
const nums = [1, 2, 3, 4, 5]
nums.map((x) => x * 2) // [2, 4, 6, 8, 10]
nums.filter((x) => x % 2 === 0) // [2, 4]
nums.flatMap((x) => [x, -x]) // [1, -1, 2, -2, 3, -3, 4, -4, 5, -5]
;[
[1, 2],
[3, [4]],
].flat() // [1, 2, 3, [4]]
;[
[1, 2],
[3, [4]],
].flat(Infinity) // [1, 2, 3, 4]Reduce and fold
Collapse an array to a single value.
| Method | Signature | Returns | Notes |
|---|---|---|---|
reduce | arr.reduce(fn, initial) | Any value | Left fold. Always pass an initial value; omitting it makes empty-array behavior undefined. |
reduceRight | arr.reduceRight(fn, initial) | Any value | Right fold; rarely needed. |
const sum = [1, 2, 3, 4].reduce((acc, x) => acc + x, 0) // 10
// Group by a key
const byStatus = items.reduce((acc, item) => {
;(acc[item.status] ??= []).push(item)
return acc
}, {})Search methods
Find elements or their positions.
| Method | Returns | Mutates | Notes |
|---|---|---|---|
find(fn) | First matching element or undefined | No | Returns the element itself. |
findIndex(fn) | Index or -1 | No | Index of the first match. |
findLast(fn) | Last matching element or undefined | No | ES2023; search from end. |
findLastIndex(fn) | Index or -1 | No | ES2023. |
indexOf(val) | Index or -1 | No | Strict equality; no function; use for primitives. |
includes(val) | Boolean | No | Returns true/false; handles NaN correctly (unlike indexOf). |
some(fn) | Boolean | No | True if any element matches. Short-circuits. |
every(fn) | Boolean | No | True if all elements match. Short-circuits. |
const users = [
{ id: 1, name: "Alice" },
{ id: 2, name: "Bob" },
]
users.find((u) => u.id === 2) // {id: 2, name: 'Bob'}
users.findIndex((u) => u.id === 2) // 1
users.some((u) => u.name === "Bob") // true
users.every((u) => u.id > 0) // true
;[NaN].includes(NaN) // true
;[NaN].indexOf(NaN) // -1 (indexOf does not handle NaN)Iteration methods
Run a side effect per element.
| Method | Returns | Mutates | Notes |
|---|---|---|---|
forEach(fn) | undefined | No | For side effects; cannot break early; cannot return a value. |
entries() | Iterator of [index, value] | No | Use in for...of loops. |
keys() | Iterator of indices | No | |
values() | Iterator of values | No |
arr.forEach((item, i) => console.log(i, item))
for (const [i, v] of arr.entries()) {
console.log(i, v)
}Prefer for...of over forEach when you need break, continue, or await inside the loop. forEach does not propagate promise rejections.
Mutating methods
These change the array in place. Avoid with React state; create a copy first.
| Method | Returns | What it does |
|---|---|---|
push(...items) | New length | Append to end. |
pop() | Removed element | Remove from end. |
unshift(...items) | New length | Prepend to start. |
shift() | Removed element | Remove from start. |
splice(start, del, ...items) | Removed elements | Insert/delete/replace at index. |
sort(fn) | Same array (mutated) | In-place sort; use toSorted for non-mutating. |
reverse() | Same array (mutated) | In-place reverse; use toReversed for non-mutating. |
fill(val, start, end) | Same array | Fill a range with a value. |
copyWithin(target, start) | Same array | Copy a slice to another position within the array. |
// Safe React state update: copy before mutating
setItems((prev) => [...prev, newItem]) // push equivalent
setItems((prev) => prev.filter((x) => x.id !== id)) // delete equivalentAccess and structural methods
| Method | Returns | Notes |
|---|---|---|
at(index) | Element or undefined | Supports negative indices: arr.at(-1) is last element. |
length | Number | Property, not a method; settable to truncate. |
Array.from(iterable) | New array | Convert any iterable or array-like. |
Array.isArray(val) | Boolean | Reliable type check; typeof returns "object" for arrays. |
Array.of(...items) | New array | Avoids Array(3) ambiguity (creates hole-y array vs 3-element array). |
join(sep) | String | Concatenate elements with separator. |
Common gotchas
sort()converts elements to strings by default.[10, 2, 1].sort()returns[1, 10, 2]. Always pass a comparator:arr.sort((a, b) => a - b).forEachreturnsundefined. Assigningconst result = arr.forEach(...)is always wrong.mapon a sparse array preserves holes.Array(3).fill(0).map(...)works;Array(3).map(...)produces holes.reducewithout aninitialvalue throws on an empty array. Pass0,[], or{}as the initial value.at(-1)is cleaner thanarr[arr.length - 1]. Both returnundefinedfor empty arrays.spliceboth mutates the array and returns the removed elements. The side-effect-plus-return pattern surprises people who expect it to work likeslice.- The
toSorted,toReversed,toSpliced, andwithmethods require Node 20+ and are not available in older browsers without a polyfill.