[ ] .map() .filter() .reduce()
Frontend

JavaScript Array Methods You Must Know

Mayur Dabhi
Mayur Dabhi
Mar 9, 2026
18 min read

Arrays are the backbone of JavaScript programming. Whether you're building a simple todo app or architecting a complex enterprise application, you'll be working with arrays constantly. Mastering array methods isn't just about writing cleaner code—it's about thinking in transformations and embracing functional programming paradigms that make your code more predictable, testable, and maintainable.

In this comprehensive guide, we'll explore every essential array method you need to know, complete with visual examples, practical use cases, and performance considerations. By the end, you'll transform from someone who loops through arrays to someone who elegantly transforms data with confidence.

What You'll Master
  • Transformation methods: map(), flatMap()
  • Filtering methods: filter(), find(), findIndex()
  • Aggregation methods: reduce(), reduceRight()
  • Testing methods: some(), every(), includes()
  • Iteration methods: forEach(), entries(), keys()
  • Mutation vs Immutation: knowing when arrays change
  • Method chaining for powerful data pipelines

Understanding Array Method Categories

Before diving into individual methods, let's understand how array methods are categorized. This mental model will help you choose the right method for any situation:

Transformers

Create new arrays with modified elements

Filters

Select elements that match criteria

Reducers

Combine elements into a single value

Searchers

Find specific elements or indices

Testers

Check conditions across elements

Iterators

Execute operations on each element

Input Array [1,2,3,4] Array Method .map(x => x*2) New Array [2,4,6,8] Original unchanged Brand new array

Most array methods don't modify the original array—they return a new one

1. The map() Method — Transform Every Element

The map() method is your go-to for transforming arrays. It creates a new array by calling a function on every element, returning the results.

Syntax
const newArray = array.map((element, index, array) => {
  // return transformed element
});
Visual Example: Doubling Numbers
1
2
3
4
→ .map(x => x * 2) →
2
4
6
8
javascript
// Basic transformation
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(num => num * 2);
// Result: [2, 4, 6, 8, 10]

// Transform objects
const users = [
  { name: 'Alice', age: 25 },
  { name: 'Bob', age: 30 },
  { name: 'Charlie', age: 35 }
];

const names = users.map(user => user.name);
// Result: ['Alice', 'Bob', 'Charlie']

// Add computed properties
const enrichedUsers = users.map(user => ({
  ...user,
  isAdult: user.age >= 18,
  greeting: `Hello, ${user.name}!`
}));

// Using index parameter
const indexed = ['a', 'b', 'c'].map((letter, index) => ({
  position: index + 1,
  letter: letter.toUpperCase()
}));
// Result: [{position: 1, letter: 'A'}, {position: 2, letter: 'B'}, ...]
Common Pitfall

Don't use map() when you don't need the returned array! If you're just iterating for side effects, use forEach() instead. Using map() without capturing its return value is wasteful.

2. The filter() Method — Keep What Matches

The filter() method creates a new array containing only elements that pass a test. It's perfect for extracting subsets of data based on conditions.

Visual Example: Filter Even Numbers
1
2
3
4
5
6
→ .filter(x => x % 2 === 0) →
2
4
6
javascript
// Filter by condition
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

const evenNumbers = numbers.filter(num => num % 2 === 0);
// Result: [2, 4, 6, 8, 10]

const greaterThanFive = numbers.filter(num => num > 5);
// Result: [6, 7, 8, 9, 10]

// Filter objects
const products = [
  { name: 'Laptop', price: 999, inStock: true },
  { name: 'Phone', price: 699, inStock: false },
  { name: 'Tablet', price: 499, inStock: true },
  { name: 'Watch', price: 299, inStock: true }
];

const availableProducts = products.filter(p => p.inStock);
const affordableProducts = products.filter(p => p.price < 500);

// Multiple conditions
const affordableAvailable = products.filter(
  p => p.inStock && p.price < 700
);

// Remove falsy values
const mixed = [0, 'hello', '', null, 42, undefined, 'world'];
const truthy = mixed.filter(Boolean);
// Result: ['hello', 42, 'world']

// Remove duplicates (with Set)
const duplicates = [1, 2, 2, 3, 3, 3, 4];
const unique = duplicates.filter((val, idx, arr) => 
  arr.indexOf(val) === idx
);
// Result: [1, 2, 3, 4]

3. The reduce() Method — The Swiss Army Knife

The reduce() method is the most powerful array method. It reduces an array to a single value by executing a reducer function on each element, accumulating results. Once you master reduce(), you can implement virtually any other array method with it!

Syntax
const result = array.reduce((accumulator, current, index, array) => {
  // return updated accumulator
}, initialValue);
How reduce() Works: Summing [1, 2, 3, 4] acc: 0, curr: 1 0 + 1 = 1 acc: 1, curr: 2 1 + 2 = 3 acc: 3, curr: 3 3 + 3 = 6 acc: 6, curr: 4 6 + 4 = 10 Result: 10 acc = accumulator (running total) | curr = current element Initial Value: 0

Reduce accumulates values step by step, passing the result to the next iteration

javascript
// Sum all numbers
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((acc, curr) => acc + curr, 0);
// Result: 15

// Find maximum value
const max = numbers.reduce((acc, curr) => 
  curr > acc ? curr : acc, 
  numbers[0]
);
// Result: 5

// Count occurrences
const fruits = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple'];
const fruitCount = fruits.reduce((acc, fruit) => {
  acc[fruit] = (acc[fruit] || 0) + 1;
  return acc;
}, {});
// Result: { apple: 3, banana: 2, orange: 1 }

// Group by property
const people = [
  { name: 'Alice', department: 'Engineering' },
  { name: 'Bob', department: 'Marketing' },
  { name: 'Charlie', department: 'Engineering' },
  { name: 'Diana', department: 'Marketing' }
];

const byDepartment = people.reduce((acc, person) => {
  const dept = person.department;
  acc[dept] = acc[dept] || [];
  acc[dept].push(person);
  return acc;
}, {});

// Flatten nested arrays
const nested = [[1, 2], [3, 4], [5, 6]];
const flat = nested.reduce((acc, arr) => [...acc, ...arr], []);
// Result: [1, 2, 3, 4, 5, 6]

// Build objects from arrays
const pairs = [['name', 'John'], ['age', 30], ['city', 'NYC']];
const obj = pairs.reduce((acc, [key, value]) => {
  acc[key] = value;
  return acc;
}, {});
// Result: { name: 'John', age: 30, city: 'NYC' }
Pro Tip: Always Provide Initial Value

Always provide an initial value to reduce(). Without it, the first element becomes the initial accumulator, which can cause unexpected behavior with empty arrays (throws error) or type mismatches.

4. The find() and findIndex() Methods — Search Efficiently

Unlike filter() which returns all matches, find() returns the first element that satisfies a condition, and findIndex() returns its index. They stop searching as soon as they find a match, making them more efficient when you only need one result.

find()

Returns the first matching element, or undefined if none found

findIndex()

Returns the index of first match, or -1 if none found

javascript
const users = [
  { id: 1, name: 'Alice', role: 'admin' },
  { id: 2, name: 'Bob', role: 'user' },
  { id: 3, name: 'Charlie', role: 'user' },
  { id: 4, name: 'Diana', role: 'moderator' }
];

// Find first admin
const admin = users.find(user => user.role === 'admin');
// Result: { id: 1, name: 'Alice', role: 'admin' }

// Find user by ID
const user = users.find(u => u.id === 3);
// Result: { id: 3, name: 'Charlie', role: 'user' }

// Find index
const moderatorIndex = users.findIndex(u => u.role === 'moderator');
// Result: 3

// Check if exists (cleaner than findIndex !== -1)
const hasAdmin = users.some(u => u.role === 'admin');
// Result: true

// Use with nullish coalescing for defaults
const guest = users.find(u => u.role === 'guest') ?? { name: 'Anonymous' };
// Result: { name: 'Anonymous' }

// findLast() and findLastIndex() - search from end (ES2023)
const numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1];
const lastThree = numbers.findLast(n => n === 3);
// Result: 3 (the second occurrence)
const lastThreeIndex = numbers.findLastIndex(n => n === 3);
// Result: 6

5. The some() and every() Methods — Test Conditions

These methods test whether elements satisfy a condition, returning true or false. They're like the array version of logical OR and AND operators.

Visual Comparison
some() - At least ONE must pass:
→ true
every() - ALL must pass:
→ false
javascript
const numbers = [1, 2, 3, 4, 5];

// some() - returns true if ANY element passes
const hasEven = numbers.some(n => n % 2 === 0);
// Result: true

const hasNegative = numbers.some(n => n < 0);
// Result: false

// every() - returns true if ALL elements pass
const allPositive = numbers.every(n => n > 0);
// Result: true

const allEven = numbers.every(n => n % 2 === 0);
// Result: false

// Practical examples
const cart = [
  { name: 'Laptop', price: 999, inStock: true },
  { name: 'Mouse', price: 29, inStock: true },
  { name: 'Keyboard', price: 79, inStock: false }
];

// Can we ship the order?
const canShip = cart.every(item => item.inStock);
// Result: false (keyboard not in stock)

// Is there anything expensive?
const hasExpensiveItem = cart.some(item => item.price > 500);
// Result: true

// Form validation
const formFields = [
  { name: 'email', valid: true },
  { name: 'password', valid: true },
  { name: 'username', valid: false }
];

const isFormValid = formFields.every(field => field.valid);
// Result: false

// Check permissions
const userPermissions = ['read', 'write'];
const requiredPermissions = ['read', 'write', 'delete'];

const hasAllPermissions = requiredPermissions.every(
  perm => userPermissions.includes(perm)
);
// Result: false (missing 'delete')

6. The forEach() Method — Side Effects Only

The forEach() method executes a function on each element but doesn't return anything. Use it when you need side effects (logging, DOM manipulation, API calls) rather than transformations.

javascript
const users = ['Alice', 'Bob', 'Charlie'];

// Logging
users.forEach(user => console.log(`Hello, ${user}!`));

// DOM manipulation
users.forEach(user => {
  const li = document.createElement('li');
  li.textContent = user;
  document.querySelector('ul').appendChild(li);
});

// With index
users.forEach((user, index) => {
  console.log(`${index + 1}. ${user}`);
});

// Modifying external state (use with caution!)
let total = 0;
[10, 20, 30].forEach(n => total += n);
console.log(total); // 60
forEach() Limitations
  • Cannot use break or continue
  • Cannot return a value (returns undefined)
  • Not chainable with other array methods
  • If you need these, use for...of loop instead

7. The includes(), indexOf(), and lastIndexOf() Methods

These methods check for element existence and locate their positions. They're simpler than find() when you're looking for exact values rather than conditions.

javascript
const fruits = ['apple', 'banana', 'orange', 'banana', 'mango'];

// includes() - returns boolean
fruits.includes('banana');      // true
fruits.includes('grape');       // false
fruits.includes('banana', 3);   // true (start from index 3)

// indexOf() - returns first index or -1
fruits.indexOf('banana');       // 1
fruits.indexOf('grape');        // -1

// lastIndexOf() - returns last index or -1
fruits.lastIndexOf('banana');   // 3

// Practical: toggle item in array
function toggleItem(array, item) {
  const index = array.indexOf(item);
  if (index === -1) {
    return [...array, item];  // Add item
  } else {
    return array.filter((_, i) => i !== index);  // Remove item
  }
}

// Check membership (cleaner with includes)
const allowedRoles = ['admin', 'moderator', 'editor'];
const userRole = 'admin';

if (allowedRoles.includes(userRole)) {
  console.log('Access granted');
}

// NaN handling - includes() works, indexOf() doesn't!
const withNaN = [1, NaN, 3];
withNaN.includes(NaN);   // true ✓
withNaN.indexOf(NaN);    // -1 ✗

8. The flat() and flatMap() Methods — Handle Nested Arrays

Modern JavaScript provides elegant ways to flatten nested arrays. flat() removes nesting, while flatMap() combines map() and flat() in one efficient operation.

Visual: Flattening Nested Arrays
[[1,2], [3,4], [5,6]] → .flat() → [1, 2, 3, 4, 5, 6]
javascript
// flat() - flatten nested arrays
const nested = [[1, 2], [3, 4], [5, 6]];
const flat = nested.flat();
// Result: [1, 2, 3, 4, 5, 6]

// Deep nesting - specify depth
const deepNested = [1, [2, [3, [4, [5]]]]];
deepNested.flat();       // [1, 2, [3, [4, [5]]]] - depth 1 (default)
deepNested.flat(2);      // [1, 2, 3, [4, [5]]]
deepNested.flat(Infinity); // [1, 2, 3, 4, 5] - flatten completely

// flatMap() - map + flat in one step
const sentences = ['Hello world', 'How are you'];
const words = sentences.flatMap(sentence => sentence.split(' '));
// Result: ['Hello', 'world', 'How', 'are', 'you']

// vs doing it separately (less efficient)
const wordsLong = sentences.map(s => s.split(' ')).flat();

// Practical: expand data
const users = [
  { name: 'Alice', emails: ['alice@work.com', 'alice@home.com'] },
  { name: 'Bob', emails: ['bob@work.com'] }
];

const allEmails = users.flatMap(user => user.emails);
// Result: ['alice@work.com', 'alice@home.com', 'bob@work.com']

// Filter while mapping
const numbers = [1, 2, 3, 4, 5];
const doubledEvens = numbers.flatMap(n => 
  n % 2 === 0 ? [n * 2] : []
);
// Result: [4, 8] - only evens, doubled

9. The sort() Method — Order Your Data

sort() arranges array elements in place. Warning: it mutates the original array! For immutable sorting, spread first or use toSorted() (ES2023).

Default Sort Gotcha

Without a compare function, sort() converts elements to strings and sorts alphabetically. This means [10, 2, 1].sort() returns [1, 10, 2], not [1, 2, 10]!

javascript
// Default string sort (alphabetical)
const fruits = ['banana', 'apple', 'cherry'];
fruits.sort();
// Result: ['apple', 'banana', 'cherry']

// Number sort - MUST provide compare function
const numbers = [10, 2, 1, 21, 5];

// Wrong! Default converts to strings
numbers.sort();
// Result: [1, 10, 2, 21, 5] ❌

// Correct - ascending
numbers.sort((a, b) => a - b);
// Result: [1, 2, 5, 10, 21] ✓

// Descending
numbers.sort((a, b) => b - a);
// Result: [21, 10, 5, 2, 1]

// Sort objects by property
const products = [
  { name: 'Laptop', price: 999 },
  { name: 'Phone', price: 699 },
  { name: 'Tablet', price: 499 }
];

// By price (ascending)
products.sort((a, b) => a.price - b.price);

// By name (alphabetical)
products.sort((a, b) => a.name.localeCompare(b.name));

// Immutable sort (ES2023)
const original = [3, 1, 2];
const sorted = original.toSorted((a, b) => a - b);
// original: [3, 1, 2] (unchanged)
// sorted: [1, 2, 3]

// Or with spread
const sortedCopy = [...original].sort((a, b) => a - b);

// Complex multi-field sort
const users = [
  { name: 'Bob', age: 30 },
  { name: 'Alice', age: 25 },
  { name: 'Alice', age: 30 }
];

users.sort((a, b) => {
  // First by name, then by age
  const nameCompare = a.name.localeCompare(b.name);
  if (nameCompare !== 0) return nameCompare;
  return a.age - b.age;
});

10. The slice() and splice() Methods — Extract and Modify

These two are often confused but serve different purposes. slice() extracts a portion without modifying the original, while splice() modifies the array in place.

Feature slice() splice()
Mutates Original No ✓ Yes ⚠️
Purpose Copy portion of array Add/remove elements
Returns New array Removed elements
Parameters (start, end) (start, deleteCount, ...items)
javascript
// slice() - extract without modifying
const arr = [0, 1, 2, 3, 4, 5];

arr.slice(2);       // [2, 3, 4, 5] - from index 2 to end
arr.slice(1, 4);    // [1, 2, 3] - from index 1 to 3 (end exclusive)
arr.slice(-2);      // [4, 5] - last 2 elements
arr.slice(1, -1);   // [1, 2, 3, 4] - exclude first and last

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

// Clone array
const clone = arr.slice();  // or [...arr]

// splice() - modify in place
const letters = ['a', 'b', 'c', 'd', 'e'];

// Remove elements
const removed = letters.splice(2, 2);  // Start at 2, remove 2
// removed: ['c', 'd']
// letters: ['a', 'b', 'e']

// Insert elements
letters.splice(2, 0, 'x', 'y');  // Start at 2, remove 0, insert 'x','y'
// letters: ['a', 'b', 'x', 'y', 'e']

// Replace elements
letters.splice(1, 2, 'NEW');  // Start at 1, remove 2, insert 'NEW'
// letters: ['a', 'NEW', 'y', 'e']

// Immutable alternative: toSpliced() (ES2023)
const original = [1, 2, 3, 4, 5];
const modified = original.toSpliced(2, 1, 'three');
// original: [1, 2, 3, 4, 5] (unchanged)
// modified: [1, 2, 'three', 4, 5]

Method Chaining — Building Data Pipelines

One of the most powerful patterns in JavaScript is chaining array methods together. Since most methods return arrays, you can create elegant data transformation pipelines.

Data .filter() .map() .sort() .reduce()

Chain methods together for powerful, readable data transformations

javascript
// Real-world example: E-commerce product processing
const products = [
  { id: 1, name: 'Laptop', price: 999, category: 'Electronics', rating: 4.5, inStock: true },
  { id: 2, name: 'Phone', price: 699, category: 'Electronics', rating: 4.8, inStock: true },
  { id: 3, name: 'Headphones', price: 199, category: 'Electronics', rating: 4.2, inStock: false },
  { id: 4, name: 'Desk Chair', price: 299, category: 'Furniture', rating: 4.0, inStock: true },
  { id: 5, name: 'Monitor', price: 449, category: 'Electronics', rating: 4.6, inStock: true }
];

// Get top-rated in-stock electronics, formatted for display
const featuredProducts = products
  .filter(p => p.category === 'Electronics')  // Only electronics
  .filter(p => p.inStock)                      // Must be in stock
  .filter(p => p.rating >= 4.5)                // High rated
  .sort((a, b) => b.rating - a.rating)         // Best first
  .map(p => ({                                 // Transform
    id: p.id,
    displayName: `${p.name} ⭐${p.rating}`,
    formattedPrice: `$${p.price.toLocaleString()}`
  }));

// Result:
// [
//   { id: 2, displayName: 'Phone ⭐4.8', formattedPrice: '$699' },
//   { id: 5, displayName: 'Monitor ⭐4.6', formattedPrice: '$449' },
//   { id: 1, displayName: 'Laptop ⭐4.5', formattedPrice: '$999' }
// ]

// Calculate total value of in-stock items
const inventoryValue = products
  .filter(p => p.inStock)
  .reduce((total, p) => total + p.price, 0);
// Result: 2446

// Group and summarize
const categorySummary = products
  .filter(p => p.inStock)
  .reduce((acc, product) => {
    const cat = product.category;
    if (!acc[cat]) {
      acc[cat] = { count: 0, totalValue: 0, avgRating: 0, ratings: [] };
    }
    acc[cat].count++;
    acc[cat].totalValue += product.price;
    acc[cat].ratings.push(product.rating);
    acc[cat].avgRating = acc[cat].ratings.reduce((a, b) => a + b) / acc[cat].ratings.length;
    return acc;
  }, {});

Quick Reference Cheat Sheet

Array Methods at a Glance

map(fn)Transform each element → new array
filter(fn)Keep matching elements → new array
reduce(fn, init)Accumulate to single value
find(fn)First matching element or undefined
findIndex(fn)Index of first match or -1
some(fn)Any element passes? → boolean
every(fn)All elements pass? → boolean
forEach(fn)Execute for each (no return)
includes(val)Contains value? → boolean
indexOf(val)Index of value or -1
flat(depth)Flatten nested arrays
flatMap(fn)Map + flatten in one step
sort(fn)Sort in place ⚠️ mutates
slice(start, end)Extract portion → new array
splice(i, n, ...items)Add/remove in place ⚠️ mutates

ES2023+ New Array Methods

Recent JavaScript versions introduced immutable alternatives to mutating methods, plus helpful new features:

javascript
// Immutable versions (ES2023) - original unchanged!
const arr = [3, 1, 2];

arr.toSorted((a, b) => a - b);    // [1, 2, 3] - sort without mutating
arr.toReversed();                  // [2, 1, 3] - reverse without mutating
arr.toSpliced(1, 1, 'new');       // [3, 'new', 2] - splice without mutating
arr.with(1, 'replaced');          // [3, 'replaced', 2] - replace at index

// findLast() and findLastIndex() - search from end
const nums = [1, 2, 3, 4, 3, 2, 1];
nums.findLast(n => n > 2);        // 3 (the second one)
nums.findLastIndex(n => n > 2);   // 4

// Array.fromAsync() - create array from async iterables
const asyncArray = await Array.fromAsync(asyncGenerator());

// Check these with your target browser support!

Performance Considerations

Performance Best Practices

  • Chain methods efficiently—each creates a new array
  • Use find() over filter()[0] when you need one element
  • Use some() over filter().length > 0 for existence checks
  • Consider for...of loops for very large arrays
  • Use reduce() to combine multiple operations
  • Avoid creating intermediate arrays when possible
javascript
// ❌ Inefficient: creates 2 intermediate arrays
const result = hugeArray
  .filter(x => x > 10)
  .filter(x => x < 100)
  .map(x => x * 2);

// ✓ Better: single reduce
const result = hugeArray.reduce((acc, x) => {
  if (x > 10 && x < 100) {
    acc.push(x * 2);
  }
  return acc;
}, []);

// ✓ Or combine filters
const result = hugeArray
  .filter(x => x > 10 && x < 100)
  .map(x => x * 2);

Conclusion

JavaScript array methods are powerful tools that can transform how you write code. By mastering map(), filter(), reduce(), and their companions, you'll write more declarative, readable, and maintainable code.

The key takeaways:

Practice these patterns in your daily coding, and they'll become second nature. Happy coding! 🚀

JavaScript Arrays Methods Functional Programming ES6+
Mayur Dabhi

Mayur Dabhi

Full Stack Developer with 5+ years of experience in Laravel, React, and modern web technologies. Passionate about writing clean code and sharing knowledge.