박하은님이 내용 정리 목적으로 출제한 문제 및 답안입니다.
- 지금까지는 함수형 도구를 사용해 하려는 일과 반복하는 일을 분리했다.
13장에서는 여러 단계를 하나로 엮은
체인
으로 복합적인 계산을 표현하는 방법을 알아본다. - 함수형 도구로 여러 단계로 하나를 조합하는 것을
체이닝
이라고 한다. 그 예시로 3회 이상 구매한 고객을 뽑은 다음 각 우수고객의 가장 비싼 구매를 가져오려면filter()
를 하고map()
을 한다. - 코드에 중첩된 리턴 구문이 있으면 무슨 일을 하는지 파악하기 어렵다.
책에서는 체인을 명확하게 만드는 방법으로
단계에 이름 붙이기
와콜백에 이름 붙이기
를 제안한다. - 각 단계의 함수를 반환하는
고차함수
를 빼내 이름을 붙이자. - 아니면 콜백을 빼내고 이름을 붙여 재사용할 수 있는 함수로 만들자.
이 방법은 고차함수를 유지하는 첫번째 방법보다 함수가 더
작다
. reduce()
를 사용해 배열numbers
의 평균을 구하는 함수average
와 두 인자를 더하는 함수plus
를 작성하시오.
function average(numbers) {
return reduce(numbers, 0, plus) / numbers.length;
}
function plus(a,b) {
return a+b;
}
filter()
와map()
는 새로운 배열을 생성하므로 최적화가 필요할 수도 있다. 이때 사용 가능한 기법인 스트림 결합이란map, filter, reduce 체인을 최적화
하는 것을 말한다. 예를 들어 값 하나에 두번filter()
를 적용하는 것은두 값에 AND 연산을 적용
하는 것과 같다. 후자의 장점은가비지 컬렉션을 적게 한
다는 것이다.- 아래 코드를 스트림 결합하시오.
const goodCustomers = filter(customers, isGoodCustomer);
const withAddresses = filter(goodCustomers, hasAddress);
// 정답
const withAddresses = filter(customers, function (customer) {
return isGoodCustomer(customer) && hasAddress(customer);
})
- 아래 코드는
map()
다음에reduce()
를 사용한다. 스트림 결합하시오.
// 각 구매별로 total 값을 구하고 그 값들을 더한 값 purchaseSum을 낸다.
const purchaseTotals = map(purchases, getPurchaseTotal);
const purchaseSum = reduce(purchaseTotals, 0, plus);
// 정답
const purchaseSum = reduce(purchases, 0, function(total, purchase) {
return total + getPurchaseTotal(purchase);
})
- 반복문을 돌면서 매 회차마다 어떤 배열에 항목을 추가하는 경우
map()
을 사용하면 좋다. 배열을 돌면서 항목을 값 하나로 만드는 경우엔reduce()
를 쓰면 좋다. - 인덱스 배열을 만드는 함수
range
를 정의하시오.
function range(start, end) {
let result = [];
for(let i=start; i<end; i++)
result.push(i);
return result;
}
- 반복문을 함수형 도구 체인으로 리팩터링할 때의 팁 3가지를 골라 설명하시오.
1. 배열 일부에 동작하는 반복문이 있다면 배열 일부를 새로운 배열로 나누기. 그리고 그 배열에 함수형 도구를 사용하기.
2. 과감하게 배열 전체를 처리하기
3. 로직이 너무 많은 일을 할 경우 작은 단계로 나누기
4. 반복문 안에 조건문을 넣어 항목을 건너뛸 경우, 앞단계에서 filter를 사용해 거르기
5. 유용한 함수를 추출하고 좋은 이름을 붙여 함수형 도구로 사용하기
- map, filter, reduce 외의 유용한 함수형 도구 하나를 골라 설명하시오.
const purchaseArrays = pluck(customers, 'purchases');
const allPurchases = concat(purchaseArrays);
// 특정 필드의 값들을 가져오는 함수
function pluck(array, field) {
return map(array, (elem) => {
return elem[field];
});
}
// 중첩된 배열을 한 단계의 배열로 만드는 함수
function concat(arrays) {
let result = [];
forEach(arrays, function(array) {
forEach(array, function(elem) {
result.push(elem);
});
});
}
// 개수를 세는 함수
function frequenciesBy(array, f) {
let result = [];
forEach(array, function (elem) {
let key = f(elem);
if(result[key]) {
result[key] += 1;
} else {
result[key] = 1;
}
});
return result;
}
- 이 책에선 데이터 저장 방법 중 하나인 '이벤트 소싱'을 언급한다.
예를 들어 고객이 추가한 제품들의 기록으로 장바구니를 만들 때, 제품 이름 뿐 아니라
순차적으로 발생하는 이벤트(동작)
을 함께 목록에 넣는 것이다. 즉 배열에 동작 이름과 제품 이름인 인자를 넣어 동작을완전한 데이터
로 표현한다.