Back to Blog
JavaScriptArraysMethodsFunctional

JavaScript Array Methods Deep Dive

Master JavaScript array methods. From map and filter to reduce and flatMap patterns.

B
Bootspring Team
Engineering
November 21, 2020
8 min read

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, doubled

Filtering 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); // -1

Testing 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); // false

Sorting 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 unchanged

Mutation 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.

Share this article

Help spread the word about Bootspring