JavaScript arrays are the most-used data structure in the language. Every method returns either a new array, a value, or modifies the original — knowing which is which prevents subtle bugs. This cheat sheet covers every built-in array method, grouped by purpose, with examples you can copy directly.
Quick-reference table
| Method | Returns | Mutates? | One-liner |
|---|---|---|---|
push(v) |
new length | ✅ | Add to end |
pop() |
removed item | ✅ | Remove from end |
unshift(v) |
new length | ✅ | Add to start |
shift() |
removed item | ✅ | Remove from start |
splice(i, n, ...v) |
removed items | ✅ | Insert/remove at index |
sort(fn) |
same array | ✅ | Sort in-place |
reverse() |
same array | ✅ | Reverse in-place |
fill(v, s, e) |
same array | ✅ | Fill with value |
copyWithin(t, s, e) |
same array | ✅ | Copy section within |
map(fn) |
new array | ❌ | Transform every element |
filter(fn) |
new array | ❌ | Keep matching elements |
flat(depth) |
new array | ❌ | Flatten nested arrays |
flatMap(fn) |
new array | ❌ | Map then flatten one level |
concat(...arrs) |
new array | ❌ | Merge arrays |
slice(s, e) |
new array | ❌ | Extract subarray |
toSorted(fn) |
new array | ❌ | Sort without mutating (ES2023) |
toReversed() |
new array | ❌ | Reverse without mutating (ES2023) |
toSpliced(i, n, ...v) |
new array | ❌ | Splice without mutating (ES2023) |
with(i, v) |
new array | ❌ | Replace index without mutating (ES2023) |
reduce(fn, init) |
any value | ❌ | Accumulate to single value |
reduceRight(fn, init) |
any value | ❌ | Reduce from right |
find(fn) |
element or undefined | ❌ | First match |
findIndex(fn) |
index or -1 | ❌ | Index of first match |
findLast(fn) |
element or undefined | ❌ | Last match (ES2023) |
findLastIndex(fn) |
index or -1 | ❌ | Index of last match (ES2023) |
indexOf(v) |
index or -1 | ❌ | First index of value |
lastIndexOf(v) |
index or -1 | ❌ | Last index of value |
includes(v) |
boolean | ❌ | Does array contain value? |
every(fn) |
boolean | ❌ | All match? |
some(fn) |
boolean | ❌ | Any match? |
forEach(fn) |
undefined | ❌ | Run function on each element |
join(sep) |
string | ❌ | Join into string |
at(i) |
element | ❌ | Get by index (supports negative) |
entries() |
iterator | ❌ | [index, value] pairs |
keys() |
iterator | ❌ | Indices |
values() |
iterator | ❌ | Values |
Array.from(v) |
new array | ❌ | Convert iterable to array |
Array.of(...v) |
new array | ❌ | Create array from args |
Array.isArray(v) |
boolean | ❌ | Is it an array? |
Adding and removing elements
These methods mutate the original array.
const a = [1, 2, 3];
a.push(4); // a = [1, 2, 3, 4], returns 4 (new length)
a.pop(); // a = [1, 2, 3], returns 4 (removed item)
a.unshift(0); // a = [0, 1, 2, 3], returns 4 (new length)
a.shift(); // a = [1, 2, 3], returns 0 (removed item)
splice is the Swiss Army knife — insert, remove, or replace at any position:
const fruits = ['apple', 'banana', 'cherry'];
// Remove 1 element at index 1
fruits.splice(1, 1); // returns ['banana'], fruits = ['apple', 'cherry']
// Insert without removing
fruits.splice(1, 0, 'mango'); // fruits = ['apple', 'mango', 'cherry']
// Replace: remove 1 and insert 2
fruits.splice(1, 1, 'kiwi', 'lime'); // fruits = ['apple', 'kiwi', 'lime', 'cherry']
Transforming arrays
map applies a function to every element and returns a new array of the same length:
const prices = [10, 20, 30];
const withTax = prices.map(p => p * 1.2); // [12, 24, 36]
const labels = prices.map((p, i) => `#${i}: €${p}`);
// ['#0: €10', '#1: €20', '#2: €30']
filter keeps elements where the callback returns truthy:
const nums = [1, 2, 3, 4, 5, 6];
const evens = nums.filter(n => n % 2 === 0); // [2, 4, 6]
const big = nums.filter(n => n > 3); // [4, 5, 6]
reduce folds the array into a single value. Always provide an initial value:
const sum = nums.reduce((acc, n) => acc + n, 0); // 21
const max = nums.reduce((a, b) => a > b ? a : b); // 6
// Group by property
const people = [
{ name: 'Alice', dept: 'eng' },
{ name: 'Bob', dept: 'hr' },
{ name: 'Carol', dept: 'eng' },
];
const byDept = people.reduce((acc, p) => {
(acc[p.dept] ??= []).push(p.name);
return acc;
}, {});
// { eng: ['Alice', 'Carol'], hr: ['Bob'] }
flatMap is map followed by flat(1) — useful when each element expands into multiple:
const sentences = ['hello world', 'foo bar'];
const words = sentences.flatMap(s => s.split(' '));
// ['hello', 'world', 'foo', 'bar']
Flattening nested arrays
const nested = [1, [2, [3, [4]]]];
nested.flat(); // [1, 2, [3, [4]]] — depth 1 (default)
nested.flat(2); // [1, 2, 3, [4]]
nested.flat(Infinity); // [1, 2, 3, 4] — fully flatten
Finding and searching
Use find/findIndex when searching by condition, indexOf/includes for exact values:
const users = [
{ id: 1, name: 'Alice', active: true },
{ id: 2, name: 'Bob', active: false },
{ id: 3, name: 'Carol', active: true },
];
users.find(u => u.id === 2); // { id: 2, name: 'Bob', active: false }
users.findIndex(u => !u.active); // 1
users.findLast(u => u.active); // { id: 3, name: 'Carol', active: true }
users.findLastIndex(u => u.active); // 2
const scores = [10, 20, 30, 20];
scores.indexOf(20); // 1 (first occurrence)
scores.lastIndexOf(20); // 3 (last occurrence)
scores.indexOf(99); // -1 (not found)
scores.includes(30); // true
Testing array contents
const nums = [2, 4, 6, 8];
nums.every(n => n % 2 === 0); // true — all even
nums.some(n => n > 5); // true — at least one > 5
nums.every(n => n > 10); // false — none > 10
nums.some(n => n < 0); // false — none negative
Short-circuit: every stops at the first false, some stops at the first true.
Sorting and reversing
sort converts elements to strings by default — always pass a comparator for numbers:
// Wrong — lexicographic sort!
[10, 9, 2, 1, 100].sort(); // [1, 10, 100, 2, 9] ❌
// Correct — numeric sort
[10, 9, 2, 1, 100].sort((a, b) => a - b); // [1, 2, 9, 10, 100] ✅
[10, 9, 2, 1, 100].sort((a, b) => b - a); // [100, 10, 9, 2, 1] (descending)
// Sort strings
['banana', 'apple', 'cherry'].sort(); // ['apple', 'banana', 'cherry']
['banana', 'apple', 'cherry'].sort((a, b) => a.localeCompare(b)); // handles accents
// Sort objects
users.sort((a, b) => a.name.localeCompare(b.name));
sort and reverse mutate in-place. Use the ES2023 immutable alternatives:
const original = [3, 1, 2];
const sorted = original.toSorted((a, b) => a - b); // [1, 2, 3]
const reversed = original.toReversed(); // [2, 1, 3]
// original is still [3, 1, 2]
Slicing and extracting
slice extracts a portion without mutating. Negative indices count from the end:
const arr = ['a', 'b', 'c', 'd', 'e'];
arr.slice(1, 3); // ['b', 'c'] — from index 1 up to (not including) 3
arr.slice(2); // ['c', 'd', 'e'] — from index 2 to end
arr.slice(-2); // ['d', 'e'] — last 2 elements
arr.slice(); // shallow copy of entire array
Combining arrays
const a = [1, 2];
const b = [3, 4];
const c = [5, 6];
a.concat(b, c); // [1, 2, 3, 4, 5, 6] — a is unchanged
[...a, ...b, ...c]; // same result with spread
Iterating
forEach runs a function on each element and always returns undefined. It cannot be chained or broken:
['a', 'b', 'c'].forEach((item, index) => {
console.log(index, item);
});
// 0 a
// 1 b
// 2 c
For the index-value pair use entries():
for (const [i, v] of ['x', 'y', 'z'].entries()) {
console.log(i, v); // 0 x, 1 y, 2 z
}
Joining and converting
['one', 'two', 'three'].join(', '); // 'one, two, three'
['one', 'two', 'three'].join(''); // 'onetwothree'
['one', 'two', 'three'].join(' | '); // 'one | two | three'
Array.from converts any iterable (string, Set, Map, NodeList, arguments):
Array.from('hello'); // ['h', 'e', 'l', 'l', 'o']
Array.from(new Set([1,1,2])); // [1, 2] — deduplicate
Array.from({length: 5}, (_, i) => i); // [0, 1, 2, 3, 4]
// Deduplicate array (common pattern)
const deduped = [...new Set([1, 2, 2, 3, 3, 3])]; // [1, 2, 3]
Accessing by index
at() supports negative indices cleanly:
const arr = ['a', 'b', 'c', 'd'];
arr.at(0); // 'a'
arr.at(-1); // 'd' — last element
arr.at(-2); // 'c' — second-to-last
// Without at():
arr[arr.length - 1]; // 'd' — more verbose
6 common mistakes
1. sort() without a comparator for numbers
// Bug: treats numbers as strings
[10, 9, 100].sort(); // [10, 100, 9] ❌
[10, 9, 100].sort((a,b)=>a-b); // [9, 10, 100] ✅
2. Mutating when you meant to copy
const original = [3, 1, 2];
original.sort((a, b) => a - b); // original is now [1, 2, 3] — mutated!
// Safe immutable approach:
const sorted = [...original].sort((a, b) => a - b);
// or:
const sorted2 = original.toSorted((a, b) => a - b); // ES2023
3. forEach is not map
// forEach always returns undefined — don't assign it
const doubled = [1, 2, 3].forEach(n => n * 2); // undefined ❌
const doubled2 = [1, 2, 3].map(n => n * 2); // [2, 4, 6] ✅
4. reduce without an initial value on empty arrays
[].reduce((acc, n) => acc + n); // TypeError: Reduce of empty array ❌
[].reduce((acc, n) => acc + n, 0); // 0 ✅ — always provide initial value
5. find vs filter confusion
const users = [{id:1}, {id:2}, {id:2}];
users.find(u => u.id === 2); // {id:2} — first match, single object
users.filter(u => u.id === 2); // [{id:2},{id:2}] — all matches, array
6. Chaining forEach (it returns undefined)
// This throws — forEach returns undefined, not an array
[1,2,3].forEach(n => n * 2).filter(n => n > 2); // TypeError ❌
// Use map instead, then chain
[1,2,3].map(n => n * 2).filter(n => n > 2); // [4, 6] ✅
FAQ
When should I use map vs forEach?
Use map when you want a transformed array back. Use forEach when you're running a side effect (logging, DOM update, API call) and don't need the result. Never use forEach to build a new array — that's what map is for.
Is for...of faster than forEach or map?
In practice the difference is negligible for most use cases. for...of supports break/continue and await, making it more flexible. map/filter/reduce are more declarative and chain naturally.
How do I remove duplicates from an array?
const unique = [...new Set(arr)];
// Or with objects by property:
const unique = arr.filter((v, i, a) => a.findIndex(t => t.id === v.id) === i);
How do I flatten an array completely?
nested.flat(Infinity); // works for any depth
What's the difference between splice and slice?
splice mutates the original array (insert/remove elements); slice returns a new subarray without touching the original. Memory trick: splice = split the original.
Can I use await inside map?
Yes, but map itself stays synchronous — it returns an array of Promises. Wrap with Promise.all:
const results = await Promise.all(ids.map(id => fetchUser(id)));