map, filter, and reduce

Three array methods, three different jobs: transform every item, keep selected items, or combine the array into one result.

The mental model

map

One input item becomes one output item. The array length stays the same.

filter

Each item passes or fails a test. The result may contain fewer items.

reduce

Each item updates an accumulator. The final result can be any value.

orders paid orders total revenue

map transforms every item

map calls your function once for each array item and stores every returned value in a new array.

Convert prices in rupees to formatted labels.
const prices = [250, 400, 125];

const labels = prices.map(price => `₹${price}`);

console.log(labels);
// ["₹250", "₹400", "₹125"]

Use the value returned by the callback. A map callback that only performs a side effect usually means forEach or a loop would say what you mean more clearly.

filter keeps matches

filter expects a truthy or falsy result. Truthy keeps the original item. Falsy leaves it out.

Keep only completed tasks.
const tasks = [
  { title: "Ship notes", done: true },
  { title: "Write tests", done: false },
  { title: "Fix typo", done: true }
];

const completed = tasks.filter(task => task.done);
// "Ship notes" and "Fix typo" remain

filter does not clone the objects it keeps. The result is a new array containing references to the same objects.

reduce carries a result forward

The accumulator is the running result. The callback returns the accumulator value for the next iteration.

Add a list of cart amounts. The initial accumulator is 0.
const amounts = [250, 400, 125];

const total = amounts.reduce(
  (sum, amount) => sum + amount,
  0
);

console.log(total); // 775
IterationsumamountReturned
10250250
2250400650
3650125775

Pass an initial value. Without one, the first item becomes the accumulator and an empty array throws a TypeError.

What each callback receives

map

(item, index, array)

filter

(item, index, array)

reduce

(accumulator, item, index, array)

The index is useful when the position belongs in the result.
const steps = ["install", "configure", "run"];

const numbered = steps.map(
  (step, index) => `${index + 1}. ${step}`
);

Chain them when each step has one job

This pipeline keeps paid orders, extracts their amounts, then adds them. Read it in the same order the data moves.

const revenue = orders
  .filter(order => order.status === "paid")
  .map(order => order.amount)
  .reduce((total, amount) => total + amount, 0);

A chain creates an intermediate array after filter and another after map. That is usually fine. For very large or performance-critical data, one loop or one carefully written reduce may avoid those allocations.

Common mistakes

  • Forgetting return with braces.

    items.map(item => { item.name }) returns an array of undefined. Add return item.name or remove the braces.

  • Mutating the original objects.

    The methods create new arrays, but objects inside them remain shared. Return a copied object when you need an immutable update.

  • Using reduce for every problem.

    If map or filter names the operation directly, use it. Dense accumulator logic is harder to scan.

Check your understanding

  1. Which method should turn [1, 2, 3] into [2, 4, 6]?
    Show answer

    map, because every input produces one transformed output.

  2. What does this return?
    [1, 2, 3, 4].filter(n => n % 2)
    Show answer

    [1, 3]. Odd remainders are 1, which is truthy. Even remainders are 0, which is falsy.

  3. Why is an initial value useful in reduce?
    Show answer

    It defines the accumulator's starting type and value, and it lets an empty array reduce safely.