Skip to content

Chaining Array Methods

Each array method you have learned returns a value — a new array or a single result. Because filter and map return arrays, you can call another method on that result immediately. This is method chaining.

const expenses = [
{ id: 1, description: 'Coffee', amount: 4.50, category: 'Food', date: '2024-01-15' },
{ id: 2, description: 'Bus pass', amount: 30.00, category: 'Transport', date: '2024-01-14' },
{ id: 3, description: 'Lunch', amount: 12.75, category: 'Food', date: '2024-01-15' },
{ id: 4, description: 'Gym membership', amount: 45.00, category: 'Health', date: '2024-01-10' },
{ id: 5, description: 'Dinner out', amount: 38.20, category: 'Food', date: '2024-01-16' },
];
// Total amount spent on Food
const foodTotal = expenses
.filter(e => e.category === 'Food')
.reduce((acc, e) => acc + e.amount, 0);
console.log(foodTotal.toFixed(2)); // '55.45'

Each line in the chain gets its own line for readability. The chain reads like English: “from expenses, keep only Food items, then sum their amounts.”

sort reorders the array in place (it mutates) and returns the same array. Always pass a comparator function — the default sort converts items to strings, which gives wrong results with numbers.

// Ascending by amount
const byAmount = [...expenses].sort((a, b) => a.amount - b.amount);

The spread ([...expenses]) creates a copy first — since sort mutates, you protect the original by sorting a copy.

The comparator receives two items a and b:

  • Return a negative numbera sorts before b
  • Return a positive numberb sorts before a
  • Return 0 → order unchanged
// Descending by amount
const byAmountDesc = [...expenses].sort((a, b) => b.amount - a.amount);
// Alphabetical by description
const byName = [...expenses].sort((a, b) => a.description.localeCompare(b.description));
// Chronological by date
const byDate = [...expenses].sort((a, b) => new Date(a.date) - new Date(b.date));

These two methods return a boolean answer about the array.

some returns true if at least one item passes the test:

const hasLargeExpense = expenses.some(e => e.amount > 40);
console.log(hasLargeExpense); // true (Gym membership is $45)

every returns true if all items pass the test:

const allUnder100 = expenses.every(e => e.amount < 100);
console.log(allUnder100); // true

Both short-circuit — some stops at the first true, every stops at the first false. Use them for validation checks.

This function returns the top-3 most expensive food expenses, formatted for display:

function getTopFoodExpenses(expenses) {
return expenses
.filter(e => e.category === 'Food')
.sort((a, b) => b.amount - a.amount)
.slice(0, 3)
.map(e => `${e.description}: $${e.amount.toFixed(2)}`);
}
console.log(getTopFoodExpenses(expenses));
// ['Dinner out: $38.20', 'Lunch: $12.75', 'Coffee: $4.50']

Reading it top to bottom: keep Food items → sort largest first → take the first three → format as strings. Each step is one focused method call.

Chaining is not always the right choice. If a chain is hard to read, break it into named variables:

// Hard to read as a one-liner
const result = expenses.filter(e => e.category === 'Food' && e.amount > 10).sort((a, b) => b.amount - a.amount).map(e => e.description);
// Better — each step is named
const foodExpenses = expenses.filter(e => e.category === 'Food' && e.amount > 10);
const sorted = [...foodExpenses].sort((a, b) => b.amount - a.amount);
const descriptions = sorted.map(e => e.description);

The named-variable version is easier to debug — you can log each step independently.

Using the expenses array from this lesson:

  1. Get all expenses with amount > 10, sorted ascending by amount, returning just the description of each.
  2. Check: does any expense cost more than $50? (Use some.)
  3. Check: do all expenses have a category property? (Use every.)
  4. Write a function getCategoryTotal(expenses, category) that returns the total amount for a given category, using chaining.
  5. Sort a copy of the array alphabetically by description and log the descriptions.
  • Method chaining calls a method on the return value of the previous method — readable when each step fits on one line.
  • sort mutates — sort a copy with [...array].sort() to protect the original.
  • The sort comparator returns negative, positive, or zero to control order.
  • some returns true if at least one item passes; every returns true if all items pass.
  • When a chain becomes hard to read, break it into named intermediate variables.