Array methods are essential for data transformation. Here's a comprehensive guide.
Transformation Methods#
1// map - transform each element
2const numbers = [1, 2, 3, 4, 5];
3const doubled = numbers.map(n => n * 2);
4// [2, 4, 6, 8, 10]
5
6// With index and array
7const indexed = numbers.map((num, index, arr) => ({
8 value: num,
9 index,
10 isLast: index === arr.length - 1,
11}));
12
13// Transform objects
14const users = [
15 { firstName: 'Alice', lastName: 'Smith' },
16 { firstName: 'Bob', lastName: 'Jones' },
17];
18
19const fullNames = users.map(u => `${u.firstName} ${u.lastName}`);
20// ['Alice Smith', 'Bob Jones']
21
22// flatMap - map and flatten
23const sentences = ['Hello world', 'How are you'];
24const words = sentences.flatMap(s => s.split(' '));
25// ['Hello', 'world', 'How', 'are', 'you']
26
27// Useful for filtering while mapping
28const results = [1, 2, 3].flatMap(n =>
29 n % 2 === 0 ? [n * 2] : []
30);
31// [4] - only even numbers, doubledFiltering Methods#
1// filter - keep elements matching condition
2const numbers = [1, 2, 3, 4, 5, 6];
3const evens = numbers.filter(n => n % 2 === 0);
4// [2, 4, 6]
5
6// Filter objects
7const users = [
8 { name: 'Alice', age: 30, active: true },
9 { name: 'Bob', age: 25, active: false },
10 { name: 'Charlie', age: 35, active: true },
11];
12
13const activeUsers = users.filter(u => u.active);
14const adults = users.filter(u => u.age >= 30);
15
16// Multiple conditions
17const activeAdults = users.filter(u => u.active && u.age >= 30);
18
19// Remove falsy values
20const mixed = [0, 1, '', 'hello', null, undefined, false, true];
21const truthy = mixed.filter(Boolean);
22// [1, 'hello', true]
23
24// Remove duplicates (simple)
25const nums = [1, 2, 2, 3, 3, 3];
26const unique = nums.filter((n, i, arr) => arr.indexOf(n) === i);
27// [1, 2, 3]Reduction Methods#
1// reduce - accumulate to single value
2const numbers = [1, 2, 3, 4, 5];
3const sum = numbers.reduce((acc, n) => acc + n, 0);
4// 15
5
6// With objects
7const items = [
8 { name: 'Apple', price: 1.5, quantity: 3 },
9 { name: 'Banana', price: 0.75, quantity: 5 },
10];
11
12const total = items.reduce(
13 (acc, item) => acc + item.price * item.quantity,
14 0
15);
16// 8.25
17
18// Build object from array
19const pairs = [['a', 1], ['b', 2], ['c', 3]];
20const obj = pairs.reduce((acc, [key, value]) => {
21 acc[key] = value;
22 return acc;
23}, {});
24// { a: 1, b: 2, c: 3 }
25
26// Group by property
27const people = [
28 { name: 'Alice', dept: 'Engineering' },
29 { name: 'Bob', dept: 'Sales' },
30 { name: 'Charlie', dept: 'Engineering' },
31];
32
33const byDept = people.reduce((acc, person) => {
34 const dept = person.dept;
35 acc[dept] = acc[dept] || [];
36 acc[dept].push(person);
37 return acc;
38}, {});
39
40// Count occurrences
41const letters = ['a', 'b', 'a', 'c', 'b', 'a'];
42const counts = letters.reduce((acc, letter) => {
43 acc[letter] = (acc[letter] || 0) + 1;
44 return acc;
45}, {});
46// { a: 3, b: 2, c: 1 }
47
48// reduceRight - reduce from right
49const nested = [[1, 2], [3, 4], [5, 6]];
50const flattened = nested.reduceRight((acc, arr) => [...arr, ...acc], []);
51// [1, 2, 3, 4, 5, 6]Search Methods#
1// find - first matching element
2const users = [
3 { id: 1, name: 'Alice' },
4 { id: 2, name: 'Bob' },
5 { id: 3, name: 'Charlie' },
6];
7
8const bob = users.find(u => u.name === 'Bob');
9// { id: 2, name: 'Bob' }
10
11const missing = users.find(u => u.name === 'David');
12// undefined
13
14// findIndex - index of first match
15const index = users.findIndex(u => u.id === 2);
16// 1
17
18// findLast / findLastIndex (ES2023)
19const numbers = [1, 2, 3, 4, 5, 4, 3];
20const lastFour = numbers.findLast(n => n === 4);
21// 4 (the second occurrence)
22const lastFourIndex = numbers.findLastIndex(n => n === 4);
23// 5
24
25// includes - check existence
26const fruits = ['apple', 'banana', 'orange'];
27fruits.includes('banana'); // true
28fruits.includes('grape'); // false
29
30// indexOf / lastIndexOf
31const nums = [1, 2, 3, 2, 1];
32nums.indexOf(2); // 1
33nums.lastIndexOf(2); // 3
34nums.indexOf(99); // -1Testing Methods#
1// every - all elements match
2const numbers = [2, 4, 6, 8];
3const allEven = numbers.every(n => n % 2 === 0);
4// true
5
6const hasOdd = [2, 4, 5, 8].every(n => n % 2 === 0);
7// false
8
9// some - at least one matches
10const users = [
11 { name: 'Alice', admin: false },
12 { name: 'Bob', admin: true },
13];
14
15const hasAdmin = users.some(u => u.admin);
16// true
17
18// Empty array behavior
19[].every(x => false); // true (vacuous truth)
20[].some(x => true); // falseSorting Methods#
1// sort - mutates original array!
2const numbers = [3, 1, 4, 1, 5, 9];
3numbers.sort((a, b) => a - b);
4// [1, 1, 3, 4, 5, 9]
5
6// Descending
7numbers.sort((a, b) => b - a);
8// [9, 5, 4, 3, 1, 1]
9
10// Sort strings
11const names = ['Charlie', 'Alice', 'Bob'];
12names.sort(); // Default: alphabetical
13// ['Alice', 'Bob', 'Charlie']
14
15// Case-insensitive
16const mixed = ['banana', 'Apple', 'cherry'];
17mixed.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
18
19// Sort objects
20const users = [
21 { name: 'Charlie', age: 35 },
22 { name: 'Alice', age: 30 },
23 { name: 'Bob', age: 25 },
24];
25
26// By age
27users.sort((a, b) => a.age - b.age);
28
29// By name
30users.sort((a, b) => a.name.localeCompare(b.name));
31
32// Multiple criteria
33users.sort((a, b) => {
34 if (a.age !== b.age) return a.age - b.age;
35 return a.name.localeCompare(b.name);
36});
37
38// toSorted (ES2023) - doesn't mutate
39const sorted = numbers.toSorted((a, b) => a - b);
40// Original array unchangedMutation Methods#
1// push / pop - end of array
2const arr = [1, 2, 3];
3arr.push(4); // Returns 4 (new length)
4arr.pop(); // Returns 4
5
6// unshift / shift - beginning of array
7arr.unshift(0); // Returns 4 (new length)
8arr.shift(); // Returns 0
9
10// splice - add/remove at index
11const items = ['a', 'b', 'c', 'd'];
12items.splice(2, 1); // Remove 1 at index 2, returns ['c']
13items.splice(2, 0, 'x'); // Insert 'x' at index 2
14items.splice(1, 2, 'y', 'z'); // Replace 2 items starting at 1
15
16// toSpliced (ES2023) - doesn't mutate
17const newItems = items.toSpliced(1, 1, 'new');
18
19// reverse - mutates
20const nums = [1, 2, 3];
21nums.reverse(); // [3, 2, 1]
22
23// toReversed (ES2023) - doesn't mutate
24const reversed = [1, 2, 3].toReversed();
25
26// fill - fill with value
27const filled = new Array(5).fill(0);
28// [0, 0, 0, 0, 0]
29
30// copyWithin - copy within array
31const arr2 = [1, 2, 3, 4, 5];
32arr2.copyWithin(0, 3); // [4, 5, 3, 4, 5]Iteration Methods#
1// forEach - side effects
2const numbers = [1, 2, 3];
3numbers.forEach((n, i) => {
4 console.log(`Index ${i}: ${n}`);
5});
6
7// Can't break out of forEach
8// Use for...of or find/some instead
9
10// entries / keys / values
11for (const [index, value] of numbers.entries()) {
12 console.log(index, value);
13}
14
15for (const key of numbers.keys()) {
16 console.log(key);
17}
18
19for (const value of numbers.values()) {
20 console.log(value);
21}Combining Methods#
1// Chain methods
2const users = [
3 { name: 'Alice', age: 30, active: true },
4 { name: 'Bob', age: 25, active: false },
5 { name: 'Charlie', age: 35, active: true },
6 { name: 'Diana', age: 28, active: true },
7];
8
9const result = users
10 .filter(u => u.active)
11 .map(u => ({ ...u, category: u.age >= 30 ? 'senior' : 'junior' }))
12 .sort((a, b) => b.age - a.age)
13 .map(u => u.name);
14// ['Charlie', 'Alice', 'Diana']
15
16// Transform and aggregate
17const orders = [
18 { product: 'A', quantity: 2, price: 10 },
19 { product: 'B', quantity: 1, price: 20 },
20 { product: 'A', quantity: 3, price: 10 },
21];
22
23const totalByProduct = orders.reduce((acc, order) => {
24 const key = order.product;
25 acc[key] = (acc[key] || 0) + order.quantity * order.price;
26 return acc;
27}, {});
28// { A: 50, B: 20 }Best Practices#
Immutability:
✓ Prefer map, filter, reduce over mutations
✓ Use toSorted, toReversed, toSpliced
✓ Spread for shallow copies
✓ Consider structuredClone for deep copies
Performance:
✓ Avoid unnecessary iterations
✓ Use appropriate methods
✓ Consider early termination
✓ Profile large datasets
Readability:
✓ Use meaningful variable names
✓ Break complex chains
✓ Document reduce accumulators
✓ Prefer specialized methods
Common Patterns:
✓ filter then map
✓ reduce for grouping
✓ some/every for validation
✓ find for single item lookup
Conclusion#
JavaScript array methods enable powerful data transformations. Master map, filter, and reduce for most use cases. Use immutable methods (ES2023) when available, chain methods for complex transformations, and choose the right method for each task.