Back to CourseIntermediate4 min read
JavaScript /

Array Methods (map, filter, reduce)

Transform, select and summarise arrays without writing loops. The three methods that change how you write JavaScript.

Bishal Biswas

Bishal Biswas

Self Learner

Published on: March 13, 2026
Last updated: September 5, 2026
Intermediate Topic

Three questions

Nearly every array operation is one of these:

  • Change every item into something else. That is map.
  • Keep only some items. That is filter.
  • Boil the whole list down to one value. That is reduce.

All three take a callback and none of them change the original array.

map

Returns a new array of the same length, with every item transformed.

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

Pulling one field out of a list of objects is the most common use:

const users = [
  { name: 'Asha', age: 28 },
  { name: 'Ben', age: 35 }
];
const names = users.map(user => user.name);
console.log(names);

Reshaping objects is the second most common:

const summaries = users.map(user => ({
  label: `${user.name} (${user.age})`,
  isAdult: user.age >= 18
}));
console.log(summaries);

The callback also receives the index:

const items = ['first', 'second', 'third'];
const numbered = items.map((item, index) => `${index + 1}. ${item}`);
console.log(numbered);

map versus forEach: map builds and returns a new array. forEach returns undefined and exists only for side effects. If you are not using the result, use forEach.

filter

Returns a new array containing only the items where the callback returned true.

const numbers = [1, 2, 3, 4, 5, 6];
const evens = numbers.filter(n => n % 2 === 0);
console.log(evens);
const products = [
  { name: 'Pen', price: 20, inStock: true },
  { name: 'Book', price: 250, inStock: false },
  { name: 'Bag', price: 800, inStock: true }
];
const available = products.filter(p => p.inStock);
const affordable = products.filter(p => p.price < 500);
console.log(available.length, affordable.length);

Combining conditions works exactly as you would expect:

const cheapAndAvailable = products.filter(p => p.inStock && p.price < 500);
console.log(cheapAndAvailable);

A neat trick for removing empty values:

const messy = ['a', '', 'b', null, 'c', undefined, 0];
console.log(messy.filter(Boolean));

reduce

The most powerful and the most confusing at first. It walks the array and builds up a single result.

const numbers = [1, 2, 3, 4];
const total = numbers.reduce((sum, n) => sum + n, 0);
console.log(total);

Two arguments to understand:

  • The callback receives the running result so far, and the current item.
  • The second argument to reduce is the starting value.

Trace it through:

// start:      sum = 0
// item 1:     sum = 0 + 1 = 1
// item 2:     sum = 1 + 2 = 3
// item 3:     sum = 3 + 3 = 6
// item 4:     sum = 6 + 4 = 10

Always pass the starting value. Without it, reduce uses the first item as the start, and it throws on an empty array.

Reduce does more than sums

Find a maximum:

const numbers = [12, 45, 7, 89, 23];
const max = numbers.reduce((best, n) => (n > best ? n : best), numbers[0]);
console.log(max);

Count occurrences:

const votes = ['yes', 'no', 'yes', 'yes', 'no'];
const tally = votes.reduce((counts, vote) => {
  counts[vote] = (counts[vote] || 0) + 1;
  return counts;
}, {});
console.log(tally);

Group items:

const people = [
  { name: 'Asha', city: 'Pune' },
  { name: 'Ben', city: 'Delhi' },
  { name: 'Chitra', city: 'Pune' }
];
const byCity = people.reduce((groups, person) => {
  const key = person.city;
  groups[key] = groups[key] || [];
  groups[key].push(person.name);
  return groups;
}, {});
console.log(byCity);

Modern JavaScript has Object.groupBy for that last one:

console.log(Object.groupBy(people, person => person.city));

Chaining

The real power comes from combining them.

const orders = [
  { item: 'Pen', price: 20, quantity: 3, status: 'delivered' },
  { item: 'Book', price: 250, quantity: 1, status: 'cancelled' },
  { item: 'Bag', price: 800, quantity: 2, status: 'delivered' }
];
const revenue = orders
  .filter(order => order.status === 'delivered')
  .map(order => order.price * order.quantity)
  .reduce((sum, amount) => sum + amount, 0);
console.log(revenue);

Read it top to bottom: keep the delivered ones, work out each total, add them up. Compare that to a for loop with an if inside and a running counter. The chain says what you want, not how to get it.

Note on performance: each step walks the array again. For a few thousand items this does not matter at all. For very large lists, a single loop is faster.

The other useful ones

const numbers = [1, 2, 3, 4, 5];
console.log(numbers.find(n => n > 3));
console.log(numbers.findIndex(n => n > 3));
console.log(numbers.some(n => n > 4));
console.log(numbers.every(n => n > 0));
console.log(numbers.flat());
console.log([[1, 2], [3, 4]].flatMap(pair => pair));
  • find returns the first match itself, filter returns all matches in an array.
  • some asks “is at least one true?”, every asks “are they all true?”.

Quick recap

  • map transforms every item and returns a new array of the same length.
  • filter keeps items where the callback is true.
  • reduce folds the array into one value, and always pass a starting value.
  • None of them change the original array.
  • Chain them to describe what you want instead of how to loop.
  • find, some and every cover the common search questions.
script.js

const orders = [
  { item: 'Pen',  price: 20,  quantity: 3, status: 'delivered' },
  { item: 'Book', price: 250, quantity: 1, status: 'cancelled' },
  { item: 'Bag',  price: 800, quantity: 2, status: 'delivered' }
];
// map: change every item into something else
console.log(orders.map(o => o.item));
// filter: keep only the ones you want
console.log(orders.filter(o => o.status === 'delivered').length);
// reduce: boil the list down to one value
const total = orders.reduce((sum, o) => sum + o.price * o.quantity, 0);
console.log('Total value:', total);
// Chaining reads top to bottom like a sentence
const revenue = orders
  .filter(o => o.status === 'delivered')
  .map(o => o.price * o.quantity)
  .reduce((sum, amount) => sum + amount, 0);
console.log('Delivered revenue:', revenue); // 1660
// reduce is not only for sums: counting
const votes = ['yes', 'no', 'yes', 'yes', 'no'];
const tally = votes.reduce((counts, vote) => {
  counts[vote] = (counts[vote] || 0) + 1;
  return counts;
}, {});
console.log(tally); // { yes: 3, no: 2 }
// reduce for grouping
const people = [
  { name: 'Asha', city: 'Pune' },
  { name: 'Ben', city: 'Delhi' },
  { name: 'Chitra', city: 'Pune' }
];
const byCity = people.reduce((groups, p) => {
  groups[p.city] = groups[p.city] || [];
  groups[p.city].push(p.name);
  return groups;
}, {});
console.log(byCity);
// Removing empty values in one step
console.log(['a', '', 'b', null, 'c'].filter(Boolean));
// The quick questions
const numbers = [1, 2, 3, 4, 5];
console.log(numbers.find(n => n > 3));    // 4, the item itself
console.log(numbers.some(n => n > 4));    // true
console.log(numbers.every(n => n > 0));   // true

Was this explanation helpful?

Your feedback helps us improve the content for everyone.