개인의 기록
  • 소개
  • 프로젝트
  • 글
  • 링크

© 2026 newgirok

← 함수형 자바스크립트

map, filter, reduce — 이터러블 기반 구현

2024년 6월 28일
JavaScript함수형 프로그래밍mapfilterreduce

자바스크립트 내장 Array.prototype.map은 배열에만 동작한다. document.querySelectorAll('*').map은 undefined다. 이터러블 프로토콜을 따르는 for...of 기반으로 구현하면 어떤 이터러블에도 동작하는 다형성을 얻을 수 있다.

map

const map = (f, iter) => {
  let res = [];
  for (const a of iter) {
    res.push(f(a));
  }
  return res;
};

내장 map이 안 되는 NodeList도 된다.

log(map(el => el.nodeName, document.querySelectorAll('*')));
// ['HTML', 'HEAD', ...]

제너레이터도 된다.

function* gen() { yield 2; yield 4; }
log(map(a => a * a, gen())); // [4, 16]

Map 자료형도 된다.

const m = new Map([['a', 10], ['b', 20]]);
log(new Map(map(([k, a]) => [k, a * 2], m)));
// Map { 'a' => 20, 'b' => 40 }

filter

const filter = (f, iter) => {
  let res = [];
  for (const a of iter) {
    if (f(a)) res.push(a);
  }
  return res;
};
log(...filter(p => p.price < 20000, products));
log(filter(n => n % 2, [1, 2, 3, 4])); // [1, 3]

reduce

누산기를 가지고 이터러블을 하나의 값으로 접는 함수다. 초기값이 없으면 첫 번째 값을 초기값으로 쓴다.

const reduce = (f, acc, iter) => {
  if (!iter) {
    iter = acc[Symbol.iterator]();
    acc = iter.next().value;
  }
  for (const a of iter) {
    acc = f(acc, a);
  }
  return acc;
};

const add = (a, b) => a + b;
log(reduce(add, 0, [1, 2, 3, 4, 5])); // 15
log(reduce(add, [1, 2, 3, 4, 5]));    // 15

상품 목록에서 가격 합산도 동일한 구조다.

log(reduce(
  (total, product) => total + product.price,
  0,
  products
));

조합

세 함수를 중첩해서 쓸 수 있다.

log(
  reduce(
    add,
    map(p => p.price,
      filter(p => p.price < 20000, products))));

이 중첩 구조를 읽기 좋게 펴는 게 다음 섹션에서 다룰 go와 pipe다.

← 이전 글제너레이터 — 이터러블을 만드는 함수
다음 글 →go, pipe, curry — 코드를 값으로 표현력 높이기