|

JavaScript 45 🧬 Array methods in depth

const nums = [1, 2, 3, 4, 5];

nums.map(n => n * 2);
nums.filter(n => n > 2);
nums.reduce((a, b) => a + b, 0);
nums.find(n => n > 3);
nums.findIndex(n => n > 3);
nums.some(n => n > 4);
nums.every(n => n > 0);
nums.includes(3);
nums.indexOf(4);
nums.slice(1, 3);
nums.concat([6, 7]);
nums.flat();
nums.flatMap(n => [n, n * 2]);
nums.sort((a, b) => a - b);
nums.reverse();
nums.join('-');
nums.forEach(n => console.log(n));

const arr = [3, 1, 2];
arr.push(4);
arr.pop();
arr.unshift(0);
arr.shift();
arr.splice(1, 2, 'x');
arr.fill(0);
arr.copyWithin(0, 2);
Array.from('abc');
Array.of(1, 2, 3);
Array.isArray([]);

Arrays come with dozens of built-in methods — the day-to-day tools that make JavaScript expressive. Some mutate the array in place; others return a new array or a value. Knowing which is which, and when to use what, is the difference between clean code and buggy code.

Key point: Every array method falls into one of four categories — mutating, non-mutating, iterating, or searching. The most common source of bugs is forgetting that methods like sort, reverse, splice, and push change the original array.


a – Iterating methods

These methods loop over an array and produce either a new array, a single value, or a side effect.

forEach — do something for each element:

const nums = [1, 2, 3];
nums.forEach(n => console.log(n));
// [ 1 ]
// [ 2 ]
// [ 3 ]

Returns undefined. Use it only for side effects — not for transforming.

map — transform each element:

const nums = [1, 2, 3];
const doubled = nums.map(n => n * 2);
console.log(doubled);
// [ [ 2, 4, 6 ] ]

console.log(nums);
// [ [ 1, 2, 3 ] ]  ← original unchanged

map returns a new array of the same length.

filter — keep elements that pass a test:

const nums = [1, 2, 3, 4, 5];
const evens = nums.filter(n => n % 2 === 0);
console.log(evens);
// [ [ 2, 4 ] ]

reduce — accumulate into a single value:

const nums = [1, 2, 3, 4];
const sum = nums.reduce((acc, n) => acc + n, 0);
console.log(sum);
// [ 10 ]

The second argument (0) is the initial accumulator. Without it, the first element is used:

const sum = nums.reduce((acc, n) => acc + n);
// [ 10 ]

reduce can build any value — arrays, objects, strings:

const words = ['a', 'b', 'c'];
const joined = words.reduce((acc, w) => acc + w, '');
console.log(joined);
// [ 'abc' ]

const counts = ['apple', 'banana', 'apple'].reduce((acc, w) => {
  acc[w] = (acc[w] || 0) + 1;
  return acc;
}, {});
console.log(counts);
// [ { apple: 2, banana: 1 } ]

reduceRight — reduce from the end:

const letters = ['a', 'b', 'c'];
const reversed = letters.reduceRight((acc, x) => acc + x, '');
console.log(reversed);
// [ 'cba' ]

flatMap — map then flatten one level:

const words = ['hello', 'world'];
const letters = words.flatMap(w => w.split(''));
console.log(letters);
// [ [ 'h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd' ] ]

Comparison of iterating methods:

MethodReturnsPurpose
forEachundefinedSide effects
mapNew arrayTransform each
filterNew arrayKeep matching
reduceAny valueAccumulate
reduceRightAny valueAccumulate right-to-left
flatMapNew arrayMap + flatten

b – Searching and testing methods

These methods look for specific elements or test a condition.

find — first match:

const users = [
  { id: 1, name: 'Alice' },
  { id: 2, name: 'Bob' },
  { id: 3, name: 'Charlie' }
];

const bob = users.find(u => u.id === 2);
console.log(bob);
// [ { id: 2, name: 'Bob' } ]

const missing = users.find(u => u.id === 99);
console.log(missing);
// [ undefined ]

Returns the first element matching, or undefined.

findIndex — index of first match:

const idx = users.findIndex(u => u.id === 2);
console.log(idx);
// [ 1 ]

const notFound = users.findIndex(u => u.id === 99);
console.log(notFound);
// [ -1 ]

findLast / findLastIndex — search from the end (ES2023):

const nums = [1, 2, 3, 4, 3, 2, 1];

console.log(nums.findLast(n => n > 2));
// [ 3 ]

console.log(nums.findLastIndex(n => n > 2));
// [ 4 ]

some — is there at least one match?

const nums = [1, 2, 3];
console.log(nums.some(n => n > 2));
// [ true ]

console.log(nums.some(n => n > 10));
// [ false ]

every — do all match?

const nums = [2, 4, 6];
console.log(nums.every(n => n % 2 === 0));
// [ true ]

console.log(nums.every(n => n > 3));
// [ false ]

includes — does the array contain a value?

const fruits = ['apple', 'banana'];
console.log(fruits.includes('banana'));
// [ true ]

console.log(fruits.includes('cherry'));
// [ false ]

console.log([1, 2, 3].includes(2));
// [ true ]

console.log([NaN].includes(NaN));
// [ true ]  ← unlike indexOf

indexOf / lastIndexOf — find the index of a value:

const nums = [1, 2, 3, 2, 1];

console.log(nums.indexOf(2));
// [ 1 ]

console.log(nums.lastIndexOf(2));
// [ 3 ]

console.log(nums.indexOf(99));
// [ -1 ]

indexOf uses strict equalityNaN won’t be found (use includes instead).

Comparison of search methods:

MethodReturnsUse for
findElement or undefinedComplex objects
findIndexIndex or -1Complex objects
findLastElement or undefinedSearch from end
findLastIndexIndex or -1Search from end
someBooleanAny match
everyBooleanAll match
includesBooleanPrimitive value
indexOfIndex or -1Primitive value
lastIndexOfIndex or -1Last occurrence

Rules of thumb:

  • Use find for objects — indexOf uses === and won’t match object references
  • Use includes for NaNindexOf(NaN) returns -1
  • Use some for “any” and every for “all”
  • Use findIndex when you need the index

c – Mutating methods

These methods change the original array. Use them with care.

push — add to end:

const arr = [1, 2];
arr.push(3);
console.log(arr);
// [ [ 1, 2, 3 ] ]

arr.push(4, 5);
console.log(arr);
// [ [ 1, 2, 3, 4, 5 ] ]

Returns the new length.

pop — remove from end:

const arr = [1, 2, 3];
const last = arr.pop();
console.log(last);
// [ 3 ]
console.log(arr);
// [ [ 1, 2 ] ]

Returns the removed element.

unshift — add to start:

const arr = [2, 3];
arr.unshift(1);
console.log(arr);
// [ [ 1, 2, 3 ] ]

Returns the new length.

shift — remove from start:

const arr = [1, 2, 3];
const first = arr.shift();
console.log(first);
// [ 1 ]
console.log(arr);
// [ [ 2, 3 ] ]

Returns the removed element.

splice — add, remove, or replace anywhere:

const arr = [1, 2, 3, 4, 5];

// Remove 2 elements starting at index 1
arr.splice(1, 2);
console.log(arr);
// [ [ 1, 4, 5 ] ]
const arr = [1, 2, 3, 4, 5];

// Replace 2 elements starting at index 1 with 'a', 'b'
arr.splice(1, 2, 'a', 'b');
console.log(arr);
// [ [ 1, 'a', 'b', 4, 5 ] ]
const arr = [1, 2, 3];

// Insert without removing
arr.splice(1, 0, 'x');
console.log(arr);
// [ [ 1, 'x', 2, 3 ] ]

Returns an array of removed elements.

sort — sort in place:

const nums = [3, 1, 4, 1, 5];
nums.sort();
console.log(nums);
// [ [ 1, 1, 3, 4, 5 ] ]

Default sort is lexicographic — converts to strings:

const nums = [10, 2, 33, 4];
nums.sort();
console.log(nums);
// [ [ 10, 2, 33, 4 ] ]  ← ❌ wrong

nums.sort((a, b) => a - b);
console.log(nums);
// [ [ 2, 4, 10, 33 ] ]  ← ✅ numeric

Numeric sort comparators:

arr.sort((a, b) => a - b);   // ascending
arr.sort((a, b) => b - a);   // descending

String sort with locale:

const names = ['Zoë', 'anna', 'Bob'];
names.sort((a, b) => a.localeCompare(b));
console.log(names);
// [ [ 'anna', 'Bob', 'Zoë' ] ]

reverse — reverse in place:

const arr = [1, 2, 3];
arr.reverse();
console.log(arr);
// [ [ 3, 2, 1 ] ]

fill — fill with a value:

const arr = [1, 2, 3, 4];
arr.fill(0);
console.log(arr);
// [ [ 0, 0, 0, 0 ] ]

const arr2 = [1, 2, 3, 4];
arr2.fill(0, 1, 3);
console.log(arr2);
// [ [ 1, 0, 0, 4 ] ]

copyWithin — copy part of the array to another position:

const arr = [1, 2, 3, 4, 5];
arr.copyWithin(0, 3);
console.log(arr);
// [ [ 4, 5, 3, 4, 5 ] ]

Comparison of mutating methods:

MethodEffectReturns
pushAdd to endNew length
popRemove from endRemoved item
unshiftAdd to startNew length
shiftRemove from startRemoved item
spliceAdd/remove/replaceRemoved items
sortSort in placeThe array
reverseReverse in placeThe array
fillFill valuesThe array
copyWithinCopy internallyThe array

Which methods mutate:

MethodMutates?
push / pop
shift / unshift
splice
sort
reverse
fill
copyWithin
map / filter
slice / concat
flat / flatMap
toSorted / toReversed
toSpliced / with

Copy-before-mutate pattern:

const original = [3, 1, 2];
const sorted = [...original].sort((a, b) => a - b);

console.log(original);
// [ [ 3, 1, 2 ] ]  ← unchanged

console.log(sorted);
// [ [ 1, 2, 3 ] ]

ES2023 non-mutating variants:

const original = [3, 1, 2];

const sorted = original.toSorted((a, b) => a - b);
const reversed = original.toReversed();
const spliced = original.toSpliced(1, 1);
const replaced = original.with(1, 99);

console.log(original);
// [ [ 3, 1, 2 ] ]  ← unchanged

Modern code should prefer the non-mutating versions.


d – Non-mutating methods

These methods return new arrays or values without changing the original.

slice — extract a portion:

const arr = [1, 2, 3, 4, 5];

console.log(arr.slice(1, 3));
// [ [ 2, 3 ] ]

console.log(arr.slice(2));
// [ [ 3, 4, 5 ] ]

console.log(arr.slice(-2));
// [ [ 4, 5 ] ]

console.log(arr.slice());
// [ [ 1, 2, 3, 4, 5 ] ]  ← shallow copy

concat — combine arrays:

const a = [1, 2];
const b = [3, 4];

console.log(a.concat(b));
// [ [ 1, 2, 3, 4 ] ]

console.log([].concat(a, b, 5));
// [ [ 1, 2, 3, 4, 5 ] ]

flat — flatten nested arrays:

const nested = [1, [2, 3], [4, [5, 6]]];

console.log(nested.flat());
// [ [ 1, 2, 3, 4, [ 5, 6 ] ] ]

console.log(nested.flat(2));
// [ [ 1, 2, 3, 4, 5, 6 ] ]

console.log(nested.flat(Infinity));
// [ [ 1, 2, 3, 4, 5, 6 ] ]

join — turn into a string:

const arr = ['a', 'b', 'c'];

console.log(arr.join());
// [ 'a,b,c' ]

console.log(arr.join('-'));
// [ 'a-b-c' ]

console.log(arr.join(''));
// [ 'abc' ]

at — access by index (supports negative):

const arr = [10, 20, 30];

console.log(arr.at(0));
// [ 10 ]

console.log(arr.at(-1));
// [ 30 ]

console.log(arr[-1]);
// [ undefined ]  ← doesn't work with brackets

toString — default string conversion:

const arr = [1, 2, 3];
console.log(arr.toString());
// [ '1,2,3' ]

Comparison of non-mutating methods:

MethodReturnsPurpose
sliceNew arrayExtract portion
concatNew arrayCombine
flatNew arrayFlatten nested
flatMapNew arrayMap + flatten
joinStringJoin elements
atElementAccess by index
toStringStringDefault string
toSortedNew arraySorted copy
toReversedNew arrayReversed copy
toSplicedNew arraySpliced copy
withNew arrayReplaced element

Complete Example Session

// ============================================
// PART 1: MAP
// ============================================

const nums = [1, 2, 3, 4, 5];
console.log(nums.map(n => n * 2));
// [ [ 2, 4, 6, 8, 10 ] ]

// ============================================
// PART 2: FILTER
// ============================================

console.log(nums.filter(n => n > 2));
// [ [ 3, 4, 5 ] ]

// ============================================
// PART 3: REDUCE
// ============================================

console.log(nums.reduce((a, b) => a + b, 0));
// [ 15 ]

// ============================================
// PART 4: FIND
// ============================================

console.log(nums.find(n => n > 3));
// [ 4 ]

console.log(nums.find(n => n > 10));
// [ undefined ]

// ============================================
// PART 5: FINDINDEX
// ============================================

console.log(nums.findIndex(n => n > 3));
// [ 3 ]

// ============================================
// PART 6: SOME / EVERY
// ============================================

console.log(nums.some(n => n > 4));
// [ true ]

console.log(nums.every(n => n > 0));
// [ true ]

// ============================================
// PART 7: INCLUDES / INDEXOF
// ============================================

console.log(nums.includes(3));
// [ true ]

console.log(nums.indexOf(4));
// [ 3 ]

console.log([NaN].includes(NaN));
// [ true ]

console.log([NaN].indexOf(NaN));
// [ -1 ]

// ============================================
// PART 8: SLICE / CONCAT
// ============================================

console.log(nums.slice(1, 3));
// [ [ 2, 3 ] ]

console.log(nums.concat([6, 7]));
// [ [ 1, 2, 3, 4, 5, 6, 7 ] ]

// ============================================
// PART 9: FLAT / FLATMAP
// ============================================

console.log([1, [2, [3]]].flat(2));
// [ [ 1, 2, 3 ] ]

console.log(['hello', 'world'].flatMap(w => w.split('')));
// [ [ 'h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd' ] ]

// ============================================
// PART 10: SORT
// ============================================

const nums2 = [10, 2, 33, 4];

console.log([...nums2].sort());
// [ [ 10, 2, 33, 4 ] ]  ← lexicographic

console.log([...nums2].sort((a, b) => a - b));
// [ [ 2, 4, 10, 33 ] ]

// ============================================
// PART 11: REVERSE
// ============================================

console.log([...nums].reverse());
// [ [ 5, 4, 3, 2, 1 ] ]

// ============================================
// PART 12: JOIN
// ============================================

console.log(nums.join('-'));
// [ '1-2-3-4-5' ]

// ============================================
// PART 13: MUTATING — PUSH / POP
// ============================================

const arr1 = [1, 2];
arr1.push(3);
console.log(arr1);
// [ [ 1, 2, 3 ] ]

arr1.pop();
console.log(arr1);
// [ [ 1, 2 ] ]

// ============================================
// PART 14: MUTATING — SPLICE
// ============================================

const arr2 = [1, 2, 3, 4, 5];
arr2.splice(1, 2, 'a', 'b');
console.log(arr2);
// [ [ 1, 'a', 'b', 4, 5 ] ]

// ============================================
// PART 15: NON-MUTATING ES2023
// ============================================

const original = [3, 1, 2];

const sorted = original.toSorted((a, b) => a - b);
console.log(sorted);
// [ [ 1, 2, 3 ] ]

console.log(original);
// [ [ 3, 1, 2 ] ]

// ============================================
// PART 16: REDUCE TO OBJECT
// ============================================

const words = ['apple', 'banana', 'apple'];
const counts = words.reduce((acc, w) => {
  acc[w] = (acc[w] || 0) + 1;
  return acc;
}, {});
console.log(counts);
// [ { apple: 2, banana: 1 } ]

// ============================================
// PART 17: CHAINING
// ============================================

const result = nums
  .filter(n => n % 2 === 0)
  .map(n => n * 10)
  .reduce((a, b) => a + b, 0);

console.log(result);
// [ 60 ]

// ============================================
// PART 18: GROUP BY (MANUAL)
// ============================================

const people = [
  { name: 'Alice', dept: 'Eng' },
  { name: 'Bob', dept: 'Sales' },
  { name: 'Charlie', dept: 'Eng' }
];

const byDept = people.reduce((acc, p) => {
  (acc[p.dept] ||= []).push(p.name);
  return acc;
}, {});
console.log(byDept);
// [ { Eng: [ 'Alice', 'Charlie' ], Sales: [ 'Bob' ] } ]

// ============================================
// PART 19: ARRAY STATIC METHODS
// ============================================

console.log(Array.from('abc'));
// [ [ 'a', 'b', 'c' ] ]

console.log(Array.from({ length: 3 }, (_, i) => i));
// [ [ 0, 1, 2 ] ]

console.log(Array.of(1, 2, 3));
// [ [ 1, 2, 3 ] ]

console.log(Array.isArray([]));
// [ true ]

// ============================================
// PART 20: FULL SCRIPT
// ============================================

const nums45 = [1, 2, 3, 4, 5];

nums45.map(n => n * 2);
nums45.filter(n => n > 2);
nums45.reduce((a, b) => a + b, 0);
nums45.find(n => n > 3);
nums45.findIndex(n => n > 3);
nums45.some(n => n > 4);
nums45.every(n => n > 0);
nums45.includes(3);
nums45.indexOf(4);
nums45.slice(1, 3);
nums45.concat([6, 7]);
nums45.flat();
nums45.flatMap(n => [n, n * 2]);
nums45.sort((a, b) => a - b);
nums45.reverse();
nums45.join('-');
nums45.forEach(n => console.log(n));

const arr45 = [3, 1, 2];
arr45.push(4);
arr45.pop();
arr45.unshift(0);
arr45.shift();
arr45.splice(1, 2, 'x');
arr45.fill(0);
arr45.copyWithin(0, 2);
Array.from('abc');
Array.of(1, 2, 3);
Array.isArray([]);

Quick Reference

Iterating Methods

MethodReturnsMutates?
forEachundefined
mapNew array
filterNew array
reduceAny value
reduceRightAny value
flatMapNew array

Searching Methods

MethodReturnsFor
findElement / undefinedObjects
findIndexIndex / -1Objects
findLastElement / undefinedFrom end
findLastIndexIndex / -1From end
someBooleanAny
everyBooleanAll
includesBooleanPrimitives, NaN
indexOfIndex / -1Primitives
lastIndexOfIndex / -1Last

Mutating Methods

MethodEffect
pushAdd end
popRemove end
unshiftAdd start
shiftRemove start
spliceAdd/remove anywhere
sortSort in place
reverseReverse in place
fillFill values
copyWithinCopy internally

Non-Mutating Methods

MethodReturns
sliceNew array
concatNew array
flatNew array
flatMapNew array
joinString
atElement
toSortedNew array (ES2023)
toReversedNew array (ES2023)
toSplicedNew array (ES2023)
withNew array (ES2023)

Static Methods

MethodPurpose
Array.from(iterable)Array from iterable
Array.from({length}, fn)Generate
Array.of(a, b, c)Create from args
Array.isArray(x)Check array

Sort Comparators

SortComparator
Numeric ascending(a, b) => a - b
Numeric descending(a, b) => b - a
String(a, b) => a.localeCompare(b)
By property(a, b) => a.x - b.x

reduce Patterns

PatternCode
Sum.reduce((a, b) => a + b, 0)
Max.reduce((a, b) => a > b ? a : b)
Count.reduce((acc, x) => (acc[x] = (acc[x] || 0) + 1, acc), {})
Group.reduce((acc, x) => ((acc[x.k] ||= []).push(x), acc), {})
Flatten.reduce((a, b) => a.concat(b), [])

Best Practices

Do This:

// Use map for transform, filter for selection
nums.map(n => n * 2);                          // ✅
nums.filter(n => n > 0);                       // ✅

// Use find for objects
users.find(u => u.id === 1);                   // ✅

// Use includes for NaN
[NaN].includes(NaN);                           // ✅

// Use numeric sort comparator
nums.sort((a, b) => a - b);                    // ✅

// Copy before mutating
const sorted = [...arr].sort();                // ✅
const sorted = arr.toSorted();                 // ✅

// Chain for readable pipelines
arr.filter(...).map(...).reduce(...);          // ✅

// Use reduce to build objects
.reduce((acc, x) => (acc[x] = 1, acc), {});    // ✅

// Use Array.from for array-likes
Array.from('hello');                           // ✅
Array.from({length: 5}, (_, i) => i);          // ✅

Don’t Do This:

// Don't use forEach to transform
arr.forEach(n => n * 2);                       // ❌ use map

// Don't use map for side effects
arr.map(n => console.log(n));                  // ❌ use forEach

// Don't use indexOf for NaN
[NaN].indexOf(NaN);                            // ❌ returns -1

// Don't forget sort mutates
const sorted = arr.sort();                     // ⚠️  changes arr
const sorted = [...arr].sort();                // ✅

// Don't sort numbers without comparator
[10, 2, 33].sort();                            // ❌ lexicographic

// Don't use find to get index
users.find(u => u.id === 1);                   // ⚠️  use findIndex

// Don't reduce without initial for empty arrays
[].reduce((a, b) => a + b);                    // ❌ TypeError
[].reduce((a, b) => a + b, 0);                 // ✅

// Don't use splice when slice works
arr.splice(0, arr.length);                     // ⚠️  mutates
arr.slice();                                   // ✅  returns copy

Common Pitfalls

PitfallProblemSolution
sort mutatesOriginal changed[...arr].sort() or toSorted
No sort comparatorLexicographic(a, b) => a - b
indexOf(NaN)Returns -1Use includes
find on object identityFails for different refsCompare properties
Empty reduceTypeErrorProvide initial value
forEach returnIgnoredUse map
map for side effectsWastes memoryUse forEach
Forgetting flat depthReturns nestedflat(Infinity)

Real-World Examples

1. Transform with map

const prices = [10, 20, 30];
const withTax = prices.map(p => p * 1.2);
console.log(withTax);
// [ [ 12, 24, 36 ] ]

2. Filter active users

const users = [
  { name: 'Alice', active: true },
  { name: 'Bob', active: false }
];

const active = users.filter(u => u.active);
console.log(active);
// [ [ { name: 'Alice', active: true } ] ]

3. Sum with reduce

const nums = [1, 2, 3, 4, 5];
console.log(nums.reduce((a, b) => a + b, 0));
// [ 15 ]

4. Find user by id

const users = [{ id: 1 }, { id: 2 }, { id: 3 }];
console.log(users.find(u => u.id === 2));
// [ { id: 2 } ]

5. Check if any match

console.log([1, 2, 3].some(n => n > 2));
// [ true ]

6. Check if all match

console.log([2, 4, 6].every(n => n % 2 === 0));
// [ true ]

7. Remove duplicates

const arr = [1, 2, 2, 3, 3, 3];
console.log([...new Set(arr)]);
// [ [ 1, 2, 3 ] ]

8. Sort objects by property

const users = [
  { name: 'Bob', age: 30 },
  { name: 'Alice', age: 25 }
];

const sorted = [...users].sort((a, b) => a.age - b.age);
console.log(sorted.map(u => u.name));
// [ [ 'Alice', 'Bob' ] ]

9. Group by property

const people = [
  { name: 'Alice', dept: 'Eng' },
  { name: 'Bob', dept: 'Sales' },
  { name: 'Charlie', dept: 'Eng' }
];

const byDept = people.reduce((acc, p) => {
  (acc[p.dept] ||= []).push(p.name);
  return acc;
}, {});
console.log(byDept);
// [ { Eng: [ 'Alice', 'Charlie' ], Sales: [ 'Bob' ] } ]

10. Word frequency

const text = 'the cat in the hat';
const counts = text.split(' ').reduce((acc, w) => {
  acc[w] = (acc[w] || 0) + 1;
  return acc;
}, {});
console.log(counts);
// [ { the: 2, cat: 1, in: 1, hat: 1 } ]

11. Flatten nested

console.log([1, [2, [3, [4]]]].flat(Infinity));
// [ [ 1, 2, 3, 4 ] ]

12. Chunk array

function chunk(arr, size) {
  return Array.from(
    { length: Math.ceil(arr.length / size) },
    (_, i) => arr.slice(i * size, i * size + size)
  );
}

console.log(chunk([1, 2, 3, 4, 5], 2));
// [ [ [ 1, 2 ], [ 3, 4 ], [ 5 ] ] ]

13. Unique by property

const users = [
  { id: 1, name: 'Alice' },
  { id: 2, name: 'Bob' },
  { id: 1, name: 'Alice2' }
];

const unique = [...new Map(users.map(u => [u.id, u])).values()];
console.log(unique);
// [ [ { id: 1, name: 'Alice2' }, { id: 2, name: 'Bob' } ] ]

14. Partition

function partition(arr, predicate) {
  return arr.reduce(
    ([pass, fail], x) => predicate(x)
      ? [[...pass, x], fail]
      : [pass, [...fail, x]],
    [[], []]
  );
}

console.log(partition([1, 2, 3, 4], n => n % 2 === 0));
// [ [ [ 2, 4 ], [ 1, 3 ] ] ]

15. Zip arrays

function zip(a, b) {
  return a.map((x, i) => [x, b[i]]);
}

console.log(zip([1, 2, 3], ['a', 'b', 'c']));
// [ [ [ 1, 'a' ], [ 2, 'b' ], [ 3, 'c' ] ] ]

16. Compact (remove falsy)

console.log([0, 1, false, 2, '', 3].filter(Boolean));
// [ [ 1, 2, 3 ] ]

17. Range

function range(start, end) {
  return Array.from({ length: end - start }, (_, i) => start + i);
}

console.log(range(1, 5));
// [ [ 1, 2, 3, 4 ] ]

18. Sum by property

const orders = [
  { total: 10 },
  { total: 20 },
  { total: 30 }
];

const sum = orders.reduce((acc, o) => acc + o.total, 0);
console.log(sum);
// [ 60 ]

19. Sort and dedupe

const arr = [3, 1, 2, 3, 1];
const result = [...new Set(arr)].sort((a, b) => a - b);
console.log(result);
// [ [ 1, 2, 3 ] ]

20. Full Script

const nums45 = [1, 2, 3, 4, 5];

nums45.map(n => n * 2);
nums45.filter(n => n > 2);
nums45.reduce((a, b) => a + b, 0);
nums45.find(n => n > 3);
nums45.findIndex(n => n > 3);
nums45.some(n => n > 4);
nums45.every(n => n > 0);
nums45.includes(3);
nums45.indexOf(4);
nums45.slice(1, 3);
nums45.concat([6, 7]);
nums45.flat();
nums45.flatMap(n => [n, n * 2]);
nums45.sort((a, b) => a - b);
nums45.reverse();
nums45.join('-');
nums45.forEach(n => console.log(n));

const arr45 = [3, 1, 2];
arr45.push(4);
arr45.pop();
arr45.unshift(0);
arr45.shift();
arr45.splice(1, 2, 'x');
arr45.fill(0);
arr45.copyWithin(0, 2);
Array.from('abc');
Array.of(1, 2, 3);
Array.isArray([]);

Visual: Mutating vs Non-Mutating

┌──────────────────────────────────────────────┐
│           MUTATING                           │
│                                              │
│  push, pop, shift, unshift                   │
│  splice, sort, reverse, fill, copyWithin     │
│                                              │
│  arr = [1, 2, 3]                             │
│  arr.push(4)                                 │
│  arr = [1, 2, 3, 4]  ← SAME array            │
│                                              │
└──────────────────────────────────────────────┘

┌──────────────────────────────────────────────┐
│           NON-MUTATING                       │
│                                              │
│  map, filter, slice, concat, flat, flatMap   │
│  toSorted, toReversed, toSpliced, with       │
│                                              │
│  arr = [1, 2, 3]                             │
│  const b = arr.map(x => x * 2)               │
│  arr = [1, 2, 3]      ← UNCHANGED            │
│  b   = [2, 4, 6]      ← NEW array            │
│                                              │
└──────────────────────────────────────────────┘

Visual: map vs forEach

┌──────────────────────────────────────────────┐
│  map                                         │
│                                              │
│  [1, 2, 3].map(x => x * 2)                   │
│       │                                      │
│       ▼                                      │
│  [2, 4, 6]  ← returns new array              │
│                                              │
│  Use when you need a new array               │
│                                              │
└──────────────────────────────────────────────┘

┌──────────────────────────────────────────────┐
│  forEach                                     │
│                                              │
│  [1, 2, 3].forEach(x => console.log(x))      │
│       │                                      │
│       ▼                                      │
│  (prints 1, 2, 3)                            │
│  returns undefined                           │
│                                              │
│  Use for side effects only                   │
│                                              │
└──────────────────────────────────────────────┘

Visual: reduce

┌──────────────────────────────────────────────┐
│  [1, 2, 3, 4].reduce((a, b) => a + b, 0)     │
│                                              │
│  acc=0, x=1  →  1                            │
│  acc=1, x=2  →  3                            │
│  acc=3, x=3  →  6                            │
│  acc=6, x=4  →  10                           │
│                                              │
│  returns 10                                  │
│                                              │
│  Fold the array into a single value          │
│                                              │
└──────────────────────────────────────────────┘

Summary

MethodCategoryReturns
mapIterateNew array
filterIterateNew array
reduceIterateAny
reduceRightIterateAny
flatMapIterateNew array
forEachIterateundefined
findSearchElement
findIndexSearchIndex
findLastSearchElement
findLastIndexSearchIndex
someSearchBoolean
everySearchBoolean
includesSearchBoolean
indexOfSearchIndex
lastIndexOfSearchIndex
pushMutateLength
popMutateElement
shiftMutateElement
unshiftMutateLength
spliceMutateRemoved
sortMutateArray
reverseMutateArray
fillMutateArray
copyWithinMutateArray
sliceReturnNew array
concatReturnNew array
flatReturnNew array
joinReturnString
atReturnElement
toSortedReturnNew array
toReversedReturnNew array
toSplicedReturnNew array
withReturnNew array
Array.fromStaticNew array
Array.ofStaticNew array
Array.isArrayStaticBoolean

Key takeaways:

  • map transforms; filter selects; reduce accumulates
  • find is for objects; includes is for primitives and NaN
  • some = any match; every = all match
  • push/pop/shift/unshift/splice/sort/reverse mutate the array
  • slice/concat/flat/flatMap/map/filter return new arrays
  • sort is lexicographic by default — always pass a comparator for numbers
  • indexOf(NaN) returns -1 — use includes instead
  • Always provide an initial value to reduce for empty arrays
  • Use toSorted/toReversed/toSpliced/with (ES2023) for non-mutating operations
  • Chain methods for clean pipelines: filter().map().reduce()
  • Array.from and Array.of create arrays from iterables or arguments
  • Array.isArray is the correct way to check for arrays

Remember: Arrays have dozens of methods, but they fall into four clear categories — iterating, searching, mutating, and returning. Know which is which and you’ll avoid the classic “why did my original array change?” bug. Reach for map/filter/reduce for transformations, find/some/every for checks, slice/concat/flat for new arrays, and only use push/splice/sort when you really mean to mutate. Master array methods, and your JavaScript becomes declarative, chainable, and readable.


Stop using slow, ad-bloated tool sites! 🤮

🔎 Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)

⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free

🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!