이 포스트는 인프런에서 진행한 유인동 님의 함수형 자바스크립트를 듣고 감명 받아서 쓴 글이다. 사실 underscore, lodash 등 함수형 패러타임으로 코드를 짤 수 있게 끔 미리 이런 함수들을 제공하는 라이브러리들을 쓰고, 이 포스트는 그닥 볼 필요가 없다. 하지만 이런 원리를 알고 접근을 하다보면 위 라이브러리를 쓴다고 하더라도 추가로 필요한 나의 코드를 함수형으로 더 짜기 유용하지 않을까?
reduce
기본적으로 reduce는 기존 데이터들을 가공해 아예 새로운 데이터를 얻고자 할 때 쓰인다. 1~6까지의 배열이 존재할 때 해당 수들을 가지고 새로운 수를 얻고자 할 때 쓰인다.
1 2 3 4 5 6 7
const nums = [1, 2, 3, 4, 5, 6]; let sum = 0; for(const num of nums) sum += num*2; console.log(sum); // 42 sum = 0; for(const num of nums) if(num%2) sum+= num; console.log(sum); // 1 + 3 + 5 = 9
뭐 딱히 추상화할 건 별로 없어보이지만 이런 반복스런 냄새들을 잘 맡고 캐치하는 것이 중요하다. 반복문 부분, 그리고 arrayLike와 객체를 위해 일단 추상화를 진행해보자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
const_each = (list, iteratee) => { if(list.toString() === '[object Object]') { const objValList = []; for(const key ofObject.keys(list)) key !== 'length' && objValList.push(list[key]); list = objValList; } for(const item of list) iteratee(item) }; // memo는 디자인 패턴 중 하나인 메모제이션 패턴을 이용한다는 것을 뜻하는 것 같다. // 또한 데이터들을 어떻게 가공할지는 반복된 함수(iteratee)에게 위임, 추상화 하였다. const_reduce = (list, iteratee, memo) => { // for(const item of list) memo = iteratee(item, memo); // 위 코드는 리스트의 반복문을 돌기 때문에 아래와 같이 추상화가 가능하다. _each(list, item => memo = iteratee(item, memo)); return memo; }; const nums = [1, 2, 3, 4, 5, 6]; console.log(_reduce(nums, (num, memo) => memo + num*2, 0)); // 42
head, tail
하지만 초기값인 메모제이션 인자가 제공되지 않으면 위 함수는 죽고 만다. 좀 더 사용하기 쉽게 함수를 만드려면 초기값은 생략이 가능해야한다.