🟨 1-9. 함수형 메서드(map, filter, reduce) 심화 — 실무 데이터 처리의 핵심 원리
1. 왜 map, filter, reduce가 중요한가
프론트엔드에서 데이터를 다룰 때, 가장 흔한 패턴은 “리스트를 가공하는 것”이다.
API에서 가져온 데이터를 정리하거나, 사용자 입력을 필터링하거나,
차트나 테이블에 맞게 변환하는 모든 과정이 여기에 속한다.
이 세 가지 메서드는 단순 반복이 아니라,
데이터를 새롭게 변형하고 요약하는 사고 방식을 가능하게 한다.
// 예시: 사용자 데이터
const users = [
{ name: "기범", age: 27 },
{ name: "민수", age: 19 },
{ name: "지현", age: 32 },
];
이 데이터를 이용해 여러 가지 처리를 해보자.
2. map — 데이터를 변형하는 방법
map은 배열의 각 요소를 순회하면서, 새로운 형태로 “변환된 결과”를 가진 새로운 배열을 만든다.
const names = users.map(user => user.name);
console.log(names); // ["기범", "민수", "지현"]
원본 배열은 변경되지 않는다.
즉, 불변성(immutability) 을 유지하면서 데이터를 가공한다는 점이 핵심이다.
조금 더 복잡한 예제를 보자.
const descriptions = users.map(user => {
return `${user.name}님은 ${user.age}세입니다.`;
});
console.log(descriptions);
// ["기범님은 27세입니다.", "민수님은 19세입니다.", "지현님은 32세입니다."]
map은 단순히 데이터를 돌리는 것이 아니라,
데이터를 표현 가능한 형태로 변환한다.
React에서 list.map(item => <Component />) 패턴이 바로 이 원리를 따른다.
3. filter — 데이터를 걸러내는 방법
filter는 조건을 만족하는 요소만 남기고 나머지는 제외한다.
const adults = users.filter(user => user.age >= 20);
console.log(adults);
// [{name:"기범",age:27},{name:"지현",age:32}]
filter는 true를 반환하는 요소만 모아서 새로운 배열을 만든다.
조건식을 조금 더 다양하게 응용할 수도 있다.
const nameWithMin = users.filter(user => user.name.includes("민"));
console.log(nameWithMin);
// [{name:"민수", age:19}]
데이터가 많을수록 filter는 깔끔한 코드의 핵심이다.
이전에는 for문과 if문을 중첩해서 썼던 로직을 한 줄로 바꿔버릴 수 있다.
4. reduce — 데이터를 축약하는 방법
reduce는 배열을 하나의 값으로 축약(combine) 하는 메서드다.
누적 합, 평균, 객체 집계 등에서 자주 사용된다.
const totalAge = users.reduce((acc, cur) => acc + cur.age, 0);
console.log(totalAge); // 78
reduce의 인자는 두 가지다.
- acc: 누적값 (accumulator)
- cur: 현재 순회 중인 요소
두 번째 인자 0은 누적값의 초기값이다.
즉, 위 코드는 이런 과정을 거친다.
- acc = 0, cur = {name: "기범", age: 27} → acc = 27
- acc = 27, cur = {name: "민수", age: 19} → acc = 46
- acc = 46, cur = {name: "지현", age: 32} → acc = 78
이렇게 배열의 모든 요소를 누적하며 하나의 값으로 만든다.
5. reduce의 심화 예시 — 객체 합치기
reduce는 단순히 합계뿐 아니라, 데이터를 객체로 재구성할 수도 있다.
const userMap = users.reduce((acc, user) => {
acc[user.name] = user.age;
return acc;
}, {});
console.log(userMap);
// { 기범: 27, 민수: 19, 지현: 32 }
이 패턴은 “배열을 객체로 변환하는 경우”에 자주 쓰인다.
API 데이터 가공, 차트용 데이터 구성 등에서 매우 유용하다.
6. map, filter, reduce의 연결 사용
이 세 가지 메서드는 개별로도 강력하지만,
조합해서 사용하면 반복문으로는 불가능한 가독성을 만든다.
예시로, “20세 이상 사용자 이름만 대문자로 변환한 리스트”를 구해보자.
const result = users
.filter(user => user.age >= 20)
.map(user => user.name.toUpperCase());
console.log(result); // ["기범", "지현"]
이렇게 filter → map 순서로 데이터를 가공하면,
필요한 데이터만 남기고 한 번에 새로운 형태로 바꿀 수 있다.
reduce까지 결합하면 더 강력해진다.
const averageAge = users
.map(u => u.age)
.reduce((acc, cur, _, arr) => acc + cur / arr.length, 0);
console.log(averageAge); // 평균 나이
데이터를 흐름으로 다루는 방식이기 때문에,
비즈니스 로직이 단순하고 읽기 쉽게 유지된다.
7. 불변성과 순수 함수의 원칙
map, filter, reduce가 함수형 메서드라고 불리는 이유는
원본 배열을 변경하지 않기 때문이다.
const original = [1, 2, 3];
const doubled = original.map(n => n * 2);
console.log(original); // [1, 2, 3]
console.log(doubled); // [2, 4, 6]
이런 특징 덕분에 함수형 프로그래밍의 핵심 원리인
순수 함수(Pure Function) 개념을 유지할 수 있다.
순수 함수란,
- 외부 상태를 변경하지 않고
- 같은 입력에는 항상 같은 출력을 반환하는 함수다.
이 원칙은 React의 렌더링 로직, Redux의 상태 관리 등에도 그대로 적용된다.
8. 실무 예제 — 상품 리스트 가격 계산
실제 예시로, 쇼핑몰의 상품 리스트를 다뤄보자.
const products = [
{ name: "노트북", price: 1200000 },
{ name: "키보드", price: 80000 },
{ name: "마우스", price: 30000 },
{ name: "모니터", price: 400000 },
];
1️⃣ 10만 원 이상 상품만 필터링
const expensive = products.filter(p => p.price >= 100000);
2️⃣ 이름만 추출
const names = expensive.map(p => p.name);
3️⃣ 총합 계산
const total = products.reduce((sum, p) => sum + p.price, 0);
최종적으로 데이터를 이렇게 시각화할 수 있다.
console.log({
expensive,
names,
total,
});
이 한 덩어리의 로직으로 ‘데이터 분석’이 끝난다.
실무에서는 이런 패턴을 하루에도 수십 번 사용하게 된다.
9. 성능과 주의할 점
- map, filter, reduce는 모두 새 배열을 반환하므로 불필요한 중첩 호출은 피하자.
- map 안에서 reduce를 중첩하거나, filter 뒤에 또 filter를 호출하면 성능이 저하될 수 있다.
- 대규모 데이터(수만 건 이상)는 for...of 와 함께 조건별로 최적화할 수도 있다.
- 하지만 대부분의 웹 프론트엔드 규모에서는 이 함수형 방식이 훨씬 가독성이 좋고 안정적이다.
10. 정리
메서드 역할 반환값 특징
| map() | 요소 변환 | 새 배열 | 원본 유지 |
| filter() | 조건 통과 요소만 남김 | 새 배열 | 조건식 필터링 |
| reduce() | 누적 계산, 요약 | 단일 값 | 유연한 구조 |
이 세 가지는 반복문을 대체하는 것이 아니라,
“데이터를 의미 있는 형태로 만드는 도구”다.
11. 마무리
map, filter, reduce는 자바스크립트의 심장이다.
데이터를 효율적으로 처리하려면 단순히 문법을 아는 것이 아니라,
“이 세 함수로 사고하는 습관”을 들여야 한다.
배열을 돌리지 말고, 변환하라.
조건문을 쓰지 말고, 걸러라.
변수에 누적하지 말고, 축약하라.
이게 함수형 사고의 핵심이다.
다음 편에서는
1-10. 클로저(Closure)와 실행 컨텍스트 심화 — 함수가 변수를 기억하는 원리
를 통해 함수의 내부 동작을 깊이 있게 파헤쳐보자.