C
JavaScript/Objects & Arrays/Lesson 12

Array Methods — *The Heart of Functional Style*

1 hr·theory
This chapter
2/2

Array Methods — *The Heart of Functional Style*

🎯 What you'll be able to do after this lesson

After completing this lesson, you'll be confident doing these 3 things:

  • ✅ Chaining map · filter · reduce · find · some · every
  • ✅ Understanding that sort mutates the original — use toSorted (ES2023) for immutability
  • ✅ Using flat · flatMap · Array.from

Keep the learning goals as a checklist — close the lesson once you can answer all of them.

The 5 Essential Methods

The One-Line Summary

Master just the functional methods of JS arrays — map·filter·reduce·find·some/every — and 90% of loops disappear. The beginning of functional thinking.

map — Transform Each Element

javascript
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(n => n * 2);    // multiply each element by 2
console.log(doubled);    // [2, 4, 6, 8, 10]
console.log(numbers);    // [1, 2, 3, 4, 5]   ← original unchanged! (returns new array)

const users = [{name:"Hong"}, {name:"Lee"}];
const names = users.map(u => u.name);       // extract only the name from each object
console.log(names);      // ["Hong", "Lee"]

Old code: for loop + push. Modern: .map() in one line.

filter — Keep Only What Passes

javascript
const numbers = [1, 2, 3, 4, 5];
const evens = numbers.filter(n => n % 2 === 0);   // keep only even numbers
console.log(evens);     // [2, 4]

const users = [
    { name: 'A', age: 20 },
    { name: 'B', age: 15 },
    { name: 'C', age: 30 }
];
const adults = users.filter(u => u.age >= 18);
console.log(adults);    // [ { name: 'A', age: 20 }, { name: 'C', age: 30 } ]

reduce — Fold Down to One

javascript
const numbers = [1, 2, 3, 4, 5];
// acc: accumulated value (starts at 0), n: current element
const sum = numbers.reduce((acc, n) => acc + n, 0);
console.log(sum);   // 15   ← 0 + 1 + 2 + 3 + 4 + 5

// 🧮 The accumulator can build objects too — count by category
const items = [
    { category: 'food' },  { category: 'drink' },
    { category: 'food' },  { category: 'food' }
];
const byCategory = items.reduce((acc, item) => {
    acc[item.category] = (acc[item.category] || 0) + 1;
    return acc;
}, {});
console.log(byCategory);   // { food: 3, drink: 1 }

reduce is the most powerful method — it can even replicate map and filter. Confusing at first, but powerful once it clicks.

find — First Match

javascript
const users = [{id:1, name:"Hong"}, {id:2, name:"Lee"}];

const user = users.find(u => u.id === 2);
console.log(user);       // { id: 2, name: 'Lee' }   ← first element matching the condition

const notFound = users.find(u => u.id === 99);
console.log(notFound);   // undefined   ← returns undefined when not found

filter returns all matches, find returns only the first one.

some / every — Truth Checks

javascript
const numbers = [1, 2, 3, 4, 5];
console.log(numbers.some(n => n > 3));    // true   ← does at least one satisfy? (4 and 5 do)
console.log(numbers.every(n => n > 0));   // true   ← do all satisfy? (all are positive)
console.log(numbers.every(n => n > 3));   // false  ← 1, 2, 3 fail the check

if (array.some(...)) expresses intent more clearly than if (array.find(...)).

Chaining — Composing It Together

javascript
const orders = [
    { id: 1, amount: 10000, status: 'PAID' },
    { id: 2, amount: 5000,  status: 'PENDING' },
    { id: 3, amount: 20000, status: 'PAID' }
];

const result = orders
    .filter(o => o.status === 'PAID')   // ① keep only paid orders → [order1, order3]
    .map(o => o.amount)                 // ② extract amounts → [10000, 20000]
    .reduce((acc, a) => acc + a, 0);    // ③ sum → 30000

console.log(result);   // 30000

The filter → map → reduce pattern mirrors SQL's WHERE → SELECT → SUM. The intent reads linearly.

More Frequently Used Methods

javascript
// sorting (watch out — mutates original)
[3, 1, 2].sort((a, b) => a - b);   // [1, 2, 3]

// reversing (mutates original)
[1, 2, 3].reverse();   // [3, 2, 1]

// checking inclusion
[1, 2, 3].includes(2);   // true

// finding the index
[1, 2, 3].indexOf(2);    // 1

// flattening
[[1, 2], [3, 4]].flat();   // [1, 2, 3, 4]

// merging
const merged = [...arr1, ...arr2];   // spread

Common Pitfalls

1. Mutating vs. returning a new array:

  • sort·reverse·push·pop·splicemutate original ⚠️
  • map·filter·slice·concatreturn a new array
javascript
const arr = [3, 1, 2];
const sorted = [...arr].sort();   // protect the original

2. forEach vs map:

javascript
arr.forEach(x => console.log(x));   // void, side effects only
arr.map(x => console.log(x));        // [undefined, undefined, ...]

forEach is for side effects only, map creates a new array. Use the right one for the job.

Quick Summary

  • map·filter·reduce = the functional trio
  • Chain them to compose logic
  • Mutating vs. non-mutating distinction is essential
  • You'll rarely ever need a for loop

find · some · every · flatMap — 5 More Methods

find — Just the First Match

javascript
const users = [
    { id: 1, name: 'A' },
    { id: 2, name: 'B' }
];
const u = users.find(x => x.id === 2);
// { id: 2, name: 'B' }

const missing = users.find(x => x.id === 999);
// undefined

Unlike filter, it stops immediately at the first match. The standard for single-record lookups.

findIndex — Just the Position Index

javascript
const idx = users.findIndex(x => x.name === 'B');   // 1
const missing = users.findIndex(x => false);         // -1

some / every — Boolean Return

javascript
const nums = [1, 2, 3, 4];
nums.some(n => n > 3);     // true (is there *at least one* greater than 3?)
nums.every(n => n > 0);    // true (are *all* of them positive?)

Frequently used for input validation and permission checks:

javascript
if (!users.every(u => u.email)) {
    throw new Error('User with missing email');
}

flat / flatMap — Flattening Nested Arrays

javascript
[1, [2, 3], [4, [5]]].flat();      // [1, 2, 3, 4, [5]]
[1, [2, 3], [4, [5]]].flat(2);     // [1, 2, 3, 4, 5]

// flatMap = map + flat(1)
const sentences = ['Hello world', 'Bye now'];
sentences.flatMap(s => s.split(' '));
// ['Hello', 'world', 'Bye', 'now']

Array.from — Array-like / Iterable → Array

javascript
Array.from('abc');             // ['a','b','c']
Array.from({ length: 5 }, (_, i) => i * 2);
// [0, 2, 4, 6, 8]

const nodeList = document.querySelectorAll('div');
Array.from(nodeList).filter(...);   // convert NodeList to an array

Chaining Patterns — *The Go-To Expression in Vibe Coding*

Transform, Filter, and Aggregate in One Go

javascript
const orders = [
    { id: 1, amount: 10000, status: 'paid' },
    { id: 2, amount: 5000,  status: 'pending' },
    { id: 3, amount: 20000, status: 'paid' },
    { id: 4, amount: 3000,  status: 'cancelled' }
];

// Total amount of paid orders
const total = orders
    .filter(o => o.status === 'paid')
    .map(o => o.amount)
    .reduce((sum, x) => sum + x, 0);
// 30000

10 lines of for loops → a 4-line chain. Nearly the standard pattern for AI-generated code.

Sort Then Take Top N

javascript
const top3 = users
    .filter(u => u.active)
    .sort((a, b) => b.score - a.score)
    .slice(0, 3);

Note: sort() mutates the original array. For immutability, use [...users].sort(...) or users.toSorted(...) (ES2023).

Group and Transform

javascript
const byStatus = orders.reduce((acc, o) => {
    (acc[o.status] ??= []).push(o);
    return acc;
}, {});
// { paid: [...], pending: [...], cancelled: [...] }

In ES2024, Object.groupBy(orders, o => o.status) does it in a single line.

Common Pitfalls

1. Forgetting the initial value in reduce

javascript
[].reduce((a, b) => a + b);   // ❌ TypeError
[].reduce((a, b) => a + b, 0); // ✅ 0

Omitting the initial value on an empty array throws an error. Always specify an initial value.

2. Causing side effects inside map

javascript
// ❌ using map just to console.log
users.map(u => console.log(u));

// ✅ use forEach or for...of instead
users.forEach(u => console.log(u));

map is meant to build a new array. If you're not using the result, forEach is the right choice.

🤖 Try asking AI like this

  • "Rewrite this for loop as a filter/map/reduce chain"
  • "From this code, sum the amount field for orders where status='paid' and print the result"
  • "Refactor this sort call to use toSorted so it doesn't mutate the original"

⚡ Try It Yourself — Chaining map · filter · reduce

Run through all 5 core methods plus chaining in one shot.
✏️ JS 코드
📟 Console output
▶ Press the Run button
⚠️ Runs in a browser sandbox — only console.log() is supported; alert/fetch are not.
Array Higher-Order Functions - JavaScript