11. Array Higher-Order Functions
`forEach` is for side effects (logging, DOM updates) and returns nothing. `map` returns a new array.
What you'll learn
- 1Choose between `forEach`, `map`, `filter`, `reduce`, `find`, `some`, `every`.
- 2Know the callback parameters (element, index, array).
- 3Build data pipelines with method chaining.
- 4Prefer a functional style that doesn't mutate the input.
- 5Use `reduce` safely with the right initial value.
Overview
`forEach` is for side effects (logging, DOM updates) and returns nothing. `map` returns a new array.
Core Concepts
1. forEach and map
`forEach` is for side effects (logging, DOM updates) and returns nothing. `map` returns a new array.
[1, 2, 3].forEach((x) => console.log(x));
const doubled = [1, 2, 3].map((x) => x * 2); // [2,4,6]2. filter, find, some, every
Select elements that satisfy a condition.
[1,2,3,4].filter((x) => x % 2 === 0); // [2,4]
[1,2,3].find((x) => x > 1); // 2 (first match)
[1,2,3].some((x) => x > 2); // true
[1,2,3].every((x) => x > 0); // true3. reduce
Fold an array down to a single value. Always specify an initial value.
const sum = [1,2,3,4].reduce((acc, x) => acc + x, 0);
const byLen = ["a","bb","ccc"].reduce((g, w) => {
(g[w.length] ??= []).push(w);
return g;
}, {});4. Chaining
Functional pipelines tend to read very nicely.
const users = [
{ name: "A", age: 17 },
{ name: "B", age: 22 },
{ name: "C", age: 30 },
];
const result = users
.filter((u) => u.age >= 18)
.map((u) => u.name)
.join(", ");Examples
| File | What it covers |
|---|---|
| `01_map.js` | Transform with map |
| `02_filter.js` | filter / find |
| `03_reduce.js` | Sum and grouping |
| `04_chain.js` | filter → map → reduce chain |
src/01_map.js
/**
* map: transform
*/
"use strict";
const nums = [1, 2, 3, 4];
const squares = nums.map((x) => x * x);
console.log(squares);
const users = [
{ name: "A", age: 20 },
{ name: "B", age: 25 },
];
console.log(users.map((u) => u.name));
src/02_filter.js
/**
* filter, find
*/
"use strict";
const nums = [1, 2, 3, 4, 5, 6];
console.log("evens =", nums.filter((x) => x % 2 === 0));
const users = [
{ id: 1, active: false },
{ id: 2, active: true },
{ id: 3, active: true },
];
console.log("first active =", users.find((u) => u.active));
console.log("actives =", users.filter((u) => u.active));
src/03_reduce.js
/**
* reduce: sum and groupBy
*/
"use strict";
const nums = [1, 2, 3, 4];
const sum = nums.reduce((acc, x) => acc + x, 0);
console.log("sum =", sum);
const words = ["js", "go", "rust", "py", "c"];
const byLen = words.reduce((g, w) => {
(g[w.length] ??= []).push(w);
return g;
}, {});
console.log("byLen =", byLen);
src/04_chain.js
/**
* Chaining
*/
"use strict";
const users = [
{ name: "A", age: 17, score: 80 },
{ name: "B", age: 22, score: 95 },
{ name: "C", age: 30, score: 60 },
{ name: "D", age: 25, score: 88 },
];
const avgAdultScore = users
.filter((u) => u.age >= 18)
.map((u) => u.score)
.reduce((acc, s, _i, arr) => acc + s / arr.length, 0);
console.log("avg adult score =", avgAdultScore);
Common Mistakes
- Calling `reduce` without an initial value, then hitting TypeError on an empty array.
- Using `map` only for side effects and throwing away the result — that's what `forEach` is for.
- Forgetting that `filter` accepts any truthy/falsy callback result, not just booleans.
- Worrying about chain performance — readability usually wins.
- Forgetting `return` inside a callback and ending up with an array of `undefined`.
FAQ
Q1. How do these compare in performance to a `for` loop?
Usually negligible. Optimize for readability first.
Q2. What about `flat` and `flatMap`?
`flat` flattens nested arrays; `flatMap` does map and flatten in one pass.
Q3. How do I run async work with map?
It produces an array of Promises — use `Promise.all(arr.map(...))`.
Practice
- `homework_01.js` — Compute the average score of an array of students with `reduce`.
- `homework_02.js` — Total revenue per category from a list of products.
homework/README.md
## homework_01.js — Use `reduce` to compute the average score for an array of students.
[ { name:"A", score:80 }, { name:"B", score:90 }, { name:"C", score:70 } ]## homework_02.js — Return an object with the total price grouped by category.
[ { name:"apple", category:"fruit", price:1000 },
{ name:"banana", category:"fruit", price:1500 },
{ name:"milk", category:"dairy", price:2500 } ]
→ { fruit: 2500, dairy: 2500 }homework/answer/homework_01.js
/**
* Homework 1: average score
*/
"use strict";
const students = [
{ name: "A", score: 80 },
{ name: "B", score: 90 },
{ name: "C", score: 70 },
];
const avg = students.reduce((acc, s, _i, arr) => acc + s.score / arr.length, 0);
console.log("avg =", avg); // 80
homework/answer/homework_02.js
/**
* Homework 2: total by category
*/
"use strict";
const products = [
{ name: "apple", category: "fruit", price: 1000 },
{ name: "banana", category: "fruit", price: 1500 },
{ name: "milk", category: "dairy", price: 2500 },
];
const totals = products.reduce((g, p) => {
g[p.category] = (g[p.category] ?? 0) + p.price;
return g;
}, {});
console.log(totals); // { fruit: 2500, dairy: 2500 }
Next Lecture
[12_Closures_and_Scope](../12_클로저와_스코프/) — Functions and state.
All lecture materials and example code are openly available on GitHub.
View on GitHub ↗