개요

Array.prototype.reduce는 배열을 하나의 값으로 축약하는 표준 API 배열의 각 요소에 대해 리듀서 함수를 순차 실행하고 누산기 값을 반환 집계, 변환, 그룹핑, 파이프라인 구성 등 다양한 패턴에 사용

구문

arr.reduce(callback[, initialValue])

  • callback에 누산 로직 정의
  • initialValue가 있으면 누산기의 시작값으로 사용, 없으면 배열의 첫 요소가 시작값

매개변수

  • callback(accumulator, currentValue, currentIndex, array)
    • accumulator: 누산된 값
    • currentValue: 현재 요소 값
    • currentIndex: 현재 인덱스
    • array: 원본 배열
  • initialValue (옵션)
    • 누산기의 초기값
    • 제공하지 않으면 배열 첫 요소가 초기값이 되어 콜백은 두 번째 요소부터 시작

반환값

  • 축약 결과로 얻은 최종 누산값

동작 방식

  • 왼쪽에서 오른쪽으로 순회하며 callback을 한 번씩 호출
  • initialValue 미제공
    • 빈 배열이면 TypeError 발생
    • 요소가 하나뿐이면 그 요소를 그대로 반환하며 callback은 호출되지 않음
  • initialValue 제공
    • 배열이 비어 있어도 initialValue를 그대로 반환하며 callback은 호출되지 않음
  • 희소 배열의 빈 슬롯은 건너뜀
  • 누산기는 어떤 타입도 가능하며 객체, 맵, 프라미스 등으로 확장 가능

주의 사항과 베스트 프랙티스

  • 가능한 항상 initialValue 지정 권장
    • 빈 배열 입력 시 예외 방지, 타입 안정성 확보
  • 누산기 불변성 유지 권장
    • 객체 누산 시 얕은 복사 또는 구조 분해 사용 고려
  • 콜백은 순수 함수 지향
    • 외부 상태 변경 최소화, 테스트 용이성 확보
  • 읽기 어려운 과도한 축약 로직은 map, filter, for…of 등으로 분리 고려
  • 희소 배열에서 빈 슬롯은 콜백이 호출되지 않음에 유의
  • 오른쪽에서 왼쪽으로 처리해야 하면 reduceRight 사용

간단 예시

합계 계산

[0, 1, 2, 3].reduce((acc, cur) => acc + cur, 0)

초기값의 차이

  • [].reduce((acc, cur) => acc + cur) → TypeError
  • [].reduce((acc, cur) => acc + cur, 0) → 0

빈 슬롯은 건너뜀

[1, , 3].reduce((acc, cur) => acc + cur, 0) // 4

객체 배열 합계

items.reduce((sum, it) => sum + it.value, 0)

중첩 배열 평탄화

nested.reduce((acc, cur) => acc.concat(cur), [])

빈도수 집계

names.reduce((m, n) => ((m[n] = (m[n] || 0) + 1), m), {})

프라미스 순차 실행

fns.reduce((p, fn) => p.then(fn), Promise.resolve(input))

map을 reduce로 구현 가능하지만 가독성 저하 가능

arr.reduce((res, v, i, a) => (res[i] = fn(v, i, a), res), [])

동작 예시 해설

초기값 없이 합계 계산 시 첫 요소가 누산기가 되고 두 번째 요소부터 콜백 실행

[0, 1, 2, 3, 4].reduce((acc, cur) => acc + cur)의 호출 순서 개념

  • 1회차 acc=0, cur=1 → 1
  • 2회차 acc=1, cur=2 → 3
  • 3회차 acc=3, cur=3 → 6
  • 4회차 acc=6, cur=4 → 10 최종 반환값 10

초기값을 10으로 주면 인덱스 0부터 시작하여 5회 호출되고 최종 20 반환

에지 케이스 체크리스트

  • 빈 배열 + initialValue 미지정 → TypeError
  • 단일 요소 배열 + initialValue 미지정 → 콜백 미호출, 단일 요소 반환
  • 빈 배열 + initialValue 지정 → 콜백 미호출, initialValue 반환
  • 희소 배열의 빈 슬롯은 미호출
  • 누산기가 참조 타입일 때 의도치 않은 공유/변경 주의

성능 팁

  • 불필요한 배열 복사 최소화 전략 설계
    • 평탄화 시 concat보다 push + 전개 연산자 혼용 비용 고려
  • 대규모 데이터 처리 시 순수 반복문 대비 오버헤드 존재 가능
    • 가독성과 유지보수 이점을 우선하되, 병목 구간은 프로파일링 후 대체 고려

함께 보면 좋은 API

  • reduceRight: 오른쪽에서 왼쪽으로 축약
  • map, filter: 전처리 또는 필터링과 조합하여 파이프라인 구성 용이
  • Set, Array.from: 중복 제거 시 대안

마무리

reduce는 배열을 하나의 값으로 축약하는 범용 도구 initialValue 지정과 콜백의 순수성 확보가 안전한 사용의 핵심 읽기 쉬운 축약 로직과 타입 일관성을 유지하면 대부분의 집계·변환 문제를 간결하게 해결 가능

참고자료