배열 다루기 — push·map·filter·reduce
매일 쓰는 배열 메서드 7개와 함수형 패턴의 기본.
배열은 JS 에서 가장 자주 만나는 자료구조입니다. ES5 이전에는 for 루프로 일일이 돌렸지만, 지금은 함수형 메서드 — map·filter·reduce 가 표준. 9편은 매일 쓰게 될 7개를 골라 정리합니다.
변형(mutate) vs 새 배열 — 가장 큰 분기
| 분류 | 메서드 | 반환 |
|---|---|---|
| 원본 변경 ⚠️ | push, pop, shift, unshift, splice, sort, reverse | 변경된 원본 일부 또는 길이 |
| 새 배열 ✅ | map, filter, slice, concat, flat, toSorted(ES2023) | 새 배열 |
| 단일 값 | find, findIndex, includes, some, every, reduce | 값/boolean/누적 |
실수 1번지. React·상태 관리에서는 원본 변경 메서드가 함정입니다. state.push(x) 가 화면 리렌더를 안 일으키죠. 새 배열 메서드나 spread([...arr, x]) 를 쓰세요. ES2023 의 toSorted/toReversed/with 는 sort/reverse 의 불변 버전.
map — 변환
const nums = [1, 2, 3, 4];
// 두 배로
const doubled = nums.map(n => n * 2); // [2, 4, 6, 8]
// 객체 변환
const users = [{name: "A", age: 30}, {name: "B", age: 25}];
const names = users.map(u => u.name); // ["A", "B"]
// 인덱스도 받기
nums.map((n, i) => `${i}: ${n}`); // ["0: 1", "1: 2", ...]
filter — 거르기
nums.filter(n => n > 2); // [3, 4]
nums.filter(n => n % 2 === 0); // [2, 4]
// Boolean 필터링 — null/undefined/0/"" 모두 제거
const arr = [1, null, 2, undefined, 3, "", 4, 0];
arr.filter(Boolean); // [1, 2, 3, 4]
map + filter 체이닝. "변환한 다음 거른다" 가 자주 나옵니다. users.map(u => u.age).filter(a => a >= 18) 같은 패턴. 한 줄로 의도가 보입니다.
reduce — 누적
// 합계
const sum = nums.reduce((acc, n) => acc + n, 0); // 10
// 최댓값
const max = nums.reduce((acc, n) => n > acc ? n : acc, -Infinity);
// 그룹화 (객체로)
const users = [
{name: "A", role: "admin"},
{name: "B", role: "user"},
{name: "C", role: "admin"},
];
const grouped = users.reduce((acc, u) => {
(acc[u.role] ??= []).push(u);
return acc;
}, {});
// { admin: [A, C], user: [B] }
// ES2024: Object.groupBy 가 새로 표준화
const grouped2 = Object.groupBy(users, u => u.role);
reduce 의 함정. 두 번째 인자(초기값) 를 빠뜨리면 첫 원소가 누적값이 되어 인덱스가 1부터 시작. 빈 배열에 reduce 호출하면 TypeError. 항상 초기값을 명시하세요.
find · findIndex · includes — 검색
// 조건 맞는 첫 원소 (없으면 undefined)
users.find(u => u.name === "A"); // {name: "A", ...}
users.findIndex(u => u.name === "A"); // 0
users.findLast(u => u.age > 18); // 마지막 매치
// 단순 포함 검사
nums.includes(3); // true
nums.indexOf(3); // 인덱스 또는 -1
// 객체 배열의 includes 는 참조 비교 (안 됨) → find/some 사용
some · every — 논리
nums.some(n => n > 3); // true (하나라도)
nums.every(n => n > 0); // true (전부)
[].every(...) // true ← 빈 배열은 항상 every == true
spread · 구조 분해 · 배열 복제
// 펴기 (concat 대체)
const a = [1, 2], b = [3, 4];
const c = [...a, ...b]; // [1,2,3,4]
const d = [0, ...a, 99, ...b]; // [0,1,2,99,3,4]
// 얕은 복제 (push 안전)
const copy = [...nums];
// 구조 분해
const [first, second, ...rest] = nums; // 1, 2, [3, 4]
const [, , third] = nums; // 3 (앞 둘 skip)
// 객체 배열 → 두 그룹
const adults = users.filter(u => u.age >= 18);
const minors = users.filter(u => u.age < 18);
// ES2024 후보: Array.prototype.partition (제안 단계)
flat · flatMap — 중첩 펼치기
[1, [2, 3], [4, [5, 6]]].flat(); // [1,2,3,4,[5,6]]
[1, [2, 3], [4, [5, 6]]].flat(2); // [1,2,3,4,5,6]
[1, [2, 3], [4, [5, 6]]].flat(Infinity); // 다 펴기
// map + flat 합친 것 (자주 씀)
const tags = ["a,b", "c", "d,e,f"];
tags.flatMap(s => s.split(",")); // ["a","b","c","d","e","f"]
sort — 항상 비교 함수와 함께
// ❌ 인자 없으면 문자열 변환 후 비교
[10, 2, 30, 4].sort(); // [10, 2, 30, 4] → ["10","2","30","4"] sort
// → [10, 2, 30, 4] ← 문자열 정렬
// ✅ 비교 함수 명시
[10, 2, 30, 4].sort((a, b) => a - b); // [2, 4, 10, 30]
[10, 2, 30, 4].sort((a, b) => b - a); // 내림차순
// 객체 정렬
users.sort((a, b) => a.age - b.age);
// 원본 보존 (ES2023)
const sorted = users.toSorted((a, b) => a.age - b.age);
10편 — 객체 다루기
객체 리터럴·구조 분해·Object.keys/values/entries 의 핵심 패턴.
📚 쉽게 배우는 자바스크립트 교재
이전: 8편 함수 · 현재: 9편 (기초) · 다음 → 10편 객체 · 진행: 9/26
이전: 8편 함수 · 현재: 9편 (기초) · 다음 → 10편 객체 · 진행: 9/26