티스토리 뷰
Currying과 Composition 모두 함수형 프로그래밍의 핵심들이다.
Currying
- f(a, b, c)처럼 단일 호출로 처리하는 함수를 f(a)(b)(c)와 같이 각각의 인수가 호출 가능한 프로세스로 호출된 후 병합되도록 변환하는 것
- currying은 함수를 호출하지 않는다. 변환한다.
- 함수의 재사용성을 높이기 위해 사용된다.
const order = store => menu =>
console.log(`${store}에서 ${menu}를 주문`)
// 호출
order('카페')('아메리카노');
order('카페')('라떼');
위 함수를 ES5로 바꾸면 아래와 같다.
function order(store) {
return function (menu) {
console.log(`${store}에서 ${menu}를 주문`)
}
}
내부 function에서 store에 접근할 수 없음 -> 가능하게 해주는게 클로저
const cafe = order('카페');
cafe의 타입은 함수
위 코드에서 중복을 없애서 아래처럼 작성할 수 있다.
cafe('아메리카노');
cafe('라떼');
위와 같은 패턴은 자바스크립트로 게임을 만들 때 많이 사용된다. (설치형 → 업데이트하기 전엔 변화가 없음)
또는, 앱을 만들거나 오프라인으로 실행되게 하겠다했을 때
커링 추가 예제
function yourPhoneNumber(start, number) {
console.log(start + number);
}
const phoneNumber = start => number => yourPhoneNumber(start, number);
const phoneNumber010 = phoneNumber('010');
phoneNumber010(12345678); // 01012345678
// 예제 출처
// https://itprogramming119.tistory.com/entry/Javascript-%EC%BB%A4%EB%A7%81Currying-%ED%95%A8%EC%88%98%EB%9E%80
Composition
아래와 같이 3개의 함수가 있고 f2는 f1의 결과를 받고, f3은 f2의 결과를 받는다고 가정했을 때
f1 : fullName // 풀네임으로 바꾸는 함수
f2 : appendAddr // 주소를 추가하는 함수
f3 : removeNames // firstName, lastName은 지우는 함수 (fullName만 필요한 경우)
위 세 가지 동작을 userDeatil이라는 함수 안에 다 작성한다면 명령형 프로그래밍이 된다.
(하나하나가 선언형이라도 그게 모여서 명령형이 되는 것)
function userDetail (user) {
// ... 풀네임되고
// ... 주소 추가하고
// ... 이름, 성 삭제하고
}
💡 명령형(절차적), 선언형 프로그래밍
https://ui.dev/imperative-vs-declarative-programming
https://dev.to/ruizb/declarative-vs-imperative-4a7l
위 userDetail 함수의 내용들을 분리하여 순차적으로 실행되도록
const fullName = (user) => ({ ...user, fullName: `${user.firstName} ${user.lastName}` });
const appendAddr = (user) => ({ ...user, addr: 'Seoul' });
const removeNames = (user) => {
delete user.firstName;
delete user.lastName;
return user;
}
const compose = (...fns) => (obj) => fns.reduce(
(c, fn) => fn(c),
obj
);
const data = compose(
fullName,
appendAddr,
removeNames,
)(user);
위 compose코드를 ES5로 reduce도 사용하지 않고 작성하면
function compose() {
var fns = arguments;
return function rfn(obj, idx) {
idx = idx || 0;
if(idx < fns.length) {
return rfn(fns[idx](obj), idx+1);
}
return obj;
}
}
만약 compose()에 아무 함수도 들어오지 않는다면 (= compose()(user) 라면)
arguments는 {}이고 ([], undefined, null 아님)
리턴값은 user가 그대로 나온다. (아무 함수도 실행되지 않았으니까)
참고 자료
🔗 [시니어코딩] React 이론 4강 - 함수형 프로그래밍의 백미, Currying과 Composition
🔗 [MDN] Array.prototype.reduce() - 함수 구성을 위한 파이프 함수
🔗 Curry and Function Composition
🔗 [freeCodeCamp] How to Use Currying and Composition in JavaScript
'🙋♀️ 기술면접 대비' 카테고리의 다른 글
CORS (0) | 2023.01.18 |
---|---|
CSR, SSR, SSG, ISR (0) | 2022.09.27 |
브라우저 렌더링 과정 (0) | 2022.09.26 |
프론트엔드 개발자 삐롱히의 개발 & 공부 기록 블로그