이터러블 프로토콜을 이용한 map, filter, reduce

Dorr·2021년 8월 15일
0

목표 : Array.prototype에 정의되어 있는 map, reduce, filter 메서드를 이터러블 객체에서도 사용할 수 있도록 추상화해보자.

Map

1. 배열에서의 map()

const arr = [1, 2, 3, 4, 5];

const newArr = arr.map((el) => el + 5);

console.log(newArr); // [6, 7, 8, 9, 10]
  • map 함수는 전단사 함수이다.
  • map 함수는 함수를 인자로 받는 고차함수이다.

2. map 함수의 추상화

일반적인 이터러블 객체에서도 적용할수 있도록 map 함수를 다시 정의해보자.

const arr = [1, 2, 3, 4, 5];

const map = () => {
  let newArr = [];
  for (const num of arr) {
    newArr.push(num);
  }
  return newArr;
};

console.log(map()); //[6, 7, 8, 9, 10]

위에서 정의한 map 함수는 외부의 arr의 상태를 변경하는 부수효과가 생기므로 순수하지 못하다. 순수함수가 되도록 수정해보자.

const arr = [1, 2, 3, 4, 5];

const map = (target) => {
  let res = [];
  for (const el of target) {
    res.push(el + 5);
  }
  return res;
};

console.log(map(arr)); //[6, 7, 8, 9, 10]

이렇게 순수함수로서 map을 정의하였다. 그러나 이 함수는 배열의 원소에 5를 더하는 것 외에는 활용할 수 없다. 따라서 재사용성을 높여줄 필요가 있다.
함수를 인자로 받게 하여 재사용성을 높여주자.

const arr = [1, 2, 3, 4, 5];

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

console.log(map((el) => el + 5, arr)); // [6, 7, 8, 9, 10]
console.log(map((el) => el * 2, arr)); // [2, 4, 6, 8, 10]

이런 식으로 함수를 인자로 받게한다면 map함수의 재사용성을 높힐 수 있다.

우리의 목표는 일반적인 이터러블 객체에서도 배열에서와 비슷한 일을 하도록 하는 것이다.

우선, 제네레이터를 이용해서 이터러블 객체를 하나 만들고 위에서 정의한 map 함수를 적용해보자.

const set = new Set(["a", "b", "c", "d", "e"]);

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

console.log(map((el) => el.toUpperCase(), set)); //["A", "B", "C", "D", "E"]

이렇게 정의한 map은 이터러블 객체에서도 활용할 수 있다.

reduce

1. Array에서의 reduce

const arr = [1, 2, 3, 4, 5];

const sum = arr.reduce((acc, currValue) => acc + currValue, 0);

console.log(sum); // 15

2. reduce 함수의 추상화

reduce 함수를 새롭게 정의

const arr = [1, 2, 3, 4, 5];

const reduce = (arr) => {
  let sum = 0;
  for (const num of arr) {
    sum += num;
  }
  return sum;
};

console.log(reduce(arr)); //15

재사용성을 높이자

const arr = [1, 2, 3, 4, 5];

const add = (a, b) => a + b;
const multiply = (a, b) => a * b;

const reduce = (f, acc, target) => {
  for (const el of target) {
    acc = f(acc, el);
  }
  return acc;
};

console.log(reduce(add, 0, arr)); //15

이터러블 프로토콜 적용

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

  for (const el of iter) {
    acc = f(acc, iter);
  }
  return acc;
};

0개의 댓글