⚙️
함수형 · ES6
중급 · 선수: 10_화살표함수
11. 배열 고차함수
`forEach` 는 부수효과(로그, DOM 조작 등)에 쓰고 반환값이 없습니다. `map` 은 새 배열을 반환합니다.
mapfilterreduce고차 함수
소요 시간
⏱ 약 1.5시간
난이도
📊 중급
선수 조건
🎯 단원 10
결과물
`forEach` 는 부수효과(로그, DOM 조작 등)에 쓰고 반환값이 없습니다. `map` 은 새 배열을 반환합니다.
이 강의에서 배우는 것
- 1`forEach`, `map`, `filter`, `reduce`, `find`, `some`, `every` 를 구분해서 쓴다.
- 2콜백의 매개변수 (요소, 인덱스, 배열) 를 안다.
- 3메서드 체이닝으로 데이터 파이프라인을 만든다.
- 4원본을 변경하지 않는 함수형 스타일을 선호한다.
- 5적절한 초기값으로 `reduce` 를 안전하게 사용한다.
소개
`forEach` 는 부수효과(로그, DOM 조작 등)에 쓰고 반환값이 없습니다. `map` 은 새 배열을 반환합니다.
핵심 개념
1. forEach 와 map
`forEach` 는 부수효과(로그, DOM 조작 등)에 쓰고 반환값이 없습니다. `map` 은 새 배열을 반환합니다.
javascript
[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
조건을 만족하는 요소를 골라냅니다.
javascript
[1,2,3,4].filter((x) => x % 2 === 0); // [2,4]
[1,2,3].find((x) => x > 1); // 2 (첫 매치)
[1,2,3].some((x) => x > 2); // true
[1,2,3].every((x) => x > 0); // true3. reduce
배열을 하나의 값으로 접습니다. 초기값을 명시하는 습관을 들이세요.
javascript
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. 체이닝
함수형 파이프라인은 가독성이 뛰어납니다.
javascript
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(", ");핵심 예제
| 파일 | 다루는 내용 |
|---|---|
| `01_map.js` | map 으로 변환 |
| `02_filter.js` | filter / find |
| `03_reduce.js` | 합계, 그룹핑 |
| `04_chain.js` | filter → map → reduce 체인 |
src/01_map.js
javascript
/**
* map: 변환
*/
"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
javascript
/**
* 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
javascript
/**
* reduce: 합계, 그룹화
*/
"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
javascript
/**
* 체이닝
*/
"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);
자주 하는 실수
- `reduce` 초기값 없이 호출했다가 빈 배열에서 TypeError.
- `map` 안에서 부수효과만 쓰고 반환값을 버린다 (`forEach` 가 적합).
- `filter` 가 boolean 이 아닌 truthy/falsy 도 통과시키는 것을 잊는다.
- 체이닝이 길어지면 성능 걱정 → 보통은 가독성이 우선.
- 콜백에서 `return` 누락으로 `undefined` 배열 생성.
FAQ
Q1. for 루프와 성능 차이?
대부분 무시할 만한 차이입니다. 가독성이 우선.
Q2. `flat`, `flatMap` 은?
중첩 배열을 펼치고 변환과 평탄화를 한 번에 합니다.
Q3. `map` 으로 비동기 작업은?
결과가 Promise 배열이 되므로 `Promise.all(arr.map(...))` 패턴을 씁니다.
과제
- `homework_01.js` — 학생 배열에서 평균 점수를 reduce 로 계산하세요.
- `homework_02.js` — 상품 배열에서 카테고리별 총액을 구하세요.
homework/README.md
## homework_01.js 학생 배열의 평균 점수를 reduce 로 구하세요.
text
[ { name:"A", score:80 }, { name:"B", score:90 }, { name:"C", score:70 } ]## homework_02.js 상품 배열에서 카테고리별 총액을 객체로 반환하세요.
text
[ { name:"사과", category:"과일", price:1000 },
{ name:"바나나", category:"과일", price:1500 },
{ name:"우유", category:"유제품", price:2500 } ]
→ { 과일: 2500, 유제품: 2500 }homework/answer/homework_01.js
javascript
/**
* 과제 1: 평균 점수
*/
"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
javascript
/**
* 과제 2: 카테고리별 총액
*/
"use strict";
const products = [
{ name: "사과", category: "과일", price: 1000 },
{ name: "바나나", category: "과일", price: 1500 },
{ name: "우유", category: "유제품", price: 2500 },
];
const totals = products.reduce((g, p) => {
g[p.category] = (g[p.category] ?? 0) + p.price;
return g;
}, {});
console.log(totals); // { 과일: 2500, 유제품: 2500 }
다음 단원
[12_클로저와_스코프](../12_클로저와_스코프/) — 함수와 상태.