2022. 8. 7. 14:23ㆍJavascript
이번 포스트에서는 많은 개발자들이 헷갈려하는 커링(currying) 기법에 대해 우선적으로 알아보고 어떻게 하면 잘 활용할 수 있는지 알아보도록 하겠습니다.
커링(Currying) 이란?
일단 정의부터 시작을 해보자면 Currying이라는 단어에 따로 뜻이 있는 건 아니고 해당 기법을 발전시킨 수학자 하스켈 커리로부터 유래했다고 합니다. 프로그래밍 세계에서 커링을 요약해보자면 아래와 같이 요약을 할 수 있습니다.
- 인자를 여러 개 받는 함수를 분리하여, 인자를 하나씩만 받는 함수로 만드는 방법
- 함수형 프로그래밍 기법 중 하나로 함수를 재사용하고 리팩트링하기 쉽게 하는 방법
특정 언어의 경우 커링이 내부적으로 구현이 되어 있기도 하지만 다중 패러다임 언어인 자바스크립트는 커링이 따로 내장되어 있지는 않기 때문에 필요에 따라 구현해 사용할 수 있습니다.
일단 이해를 돕기 위해 커링에 대해 설명할 때 가장 많이 나오는 기초 예제부터 한번 살펴보도록 하겠습니다.
// 커링 적용전 곱셈함수
const multiply_v1 = (a, b, c) => {
return a * b * c;
}
// 커링 적용한 곱셈함수
const multiply_v2 = (a) => (b) => (c) => {
return a * b * c;
}
위 예제의 첫 번째 함수는 커링을 적용하기 전에 3개의 인자를 받아 곱셈 연산을 하고 있고 두 번째 함수는 커링을 적용해 인자를 하나씩만 받는 함수로 변형해 사용하고 있습니다.
화살표 함수를 사용하지 않고 함수 선언문으로 두 번째 함수를 작성해보면 아래와 같이 작성할 수 있습니다
function multiply_v2(a) {
return function (b) {
return function (c) {
return a * b * c
}
}
}
// 호출: multiple_v2(2)(3)(4) = 24
보시다시피 첫 번째 함수처럼 a, b, c를 곱한 결괏값을 바로 반환하지 않고 새로운 인자 b와 c를 순차적으로 요구하는 익명 함수를 반환하게 됩니다. 가장 내부에 있는 함수가 반환되어 호출되었을 때 비로소 첫 번째 함수와 같이 3 인자를 곱한 결괏값을 반환하게 됩니다.
해당 예제를 보면서 첫 번째 함수가 훨씬 이해하기 쉽고 직관적인데 왜 굳이 커링을 사용하는지 의아해하시는 분들도 계실 겁니다. 물론 함수 선언 방식에 있어서는 필자도 이에 동의하지만 커링은 해당 함수를 호출하고 재사용할 때 진가를 발휘합니다.
예를 들어서 장바구니에 담긴 물건들의 가격을 계산한다고 가정을 해보겠습니다.
커링을 적용하기 전 multiple_v1 함수로는 아래와 같이 작성할 수 있습니다.
const VAT = 1.05; // 5% VAT
// a -> 부과세, b -> 가격, c-> 갯수
const shirts_price = multiply_v1(VAT, 20000, 4);
const pants_price = multiply_v1(VAT, 15000, 4);
이제 커링을 적용한 함수를 사용했을 때는 어떤 식으로 사용 가능한지 확인해보겠습니다.
const VAT = 1.05;
const multiply_VAT = multiply_v2(VAT); // 부가세가 첫번째 인자로 전달된 함수를 multply_VAT 변수에 선언
const shirts_price = multiply_VAT(20000)(4);
const pants_price = multiply_VAT(15000)(2);
커링을 사용하지 않았을 경우 VAT값은 고정값임에도 불구하고 매번 전달해줘야 했지만 커링을 적용한 뒤에는 부가세가 인자로 전달된 multiply_VAT 함수를 가격과 수량만 별도의 인자로 전달하여 호출해주었습니다. 현재는 인자의 개수가 애초에 읽기 힘들 정도로 많은 정도가 아니기 때문에 큰 변화라 느껴지진 않을 수는 있지만 추후에 인자가 많아지거나 재사용의 필요성이 느껴질 경우 커링 기법은 이와 같이 많은 도움이 될 수 있습니다.
Currying(커링)으로 OnClick 핸들러 작성하기
실전에서 적용할 수 있는 한 가지 예시를 더 들어보도록 하겠습니다. 위에 적용했던 방식처럼 커링 기법을 통해 이벤트 핸들러를 좀 더 깔끔하게 작성할 수가 있습니다.
우선 기존의 이벤트 핸들러가 작동하는 방식부터 보도록 하겠습니다.
// 인자가 없을경우
<button onClick={handleClick}>전송</button>
// 인자가 있을경우 (익명 함수로 전달)
<button onClick={() => handleClick(value)}>전송</button>
인자가 없을 경우 그냥 핸들러 함수(handleClick)만 정의한 뒤 넘겨주기만 하면 되지만, 인자가 있을 경우는 함수가 바로 호출되지 않도록 익명 함수로 전달을 해줘야 합니다.
익명 함수로 전달하는 방법에 문제가 있는 건 아니지만 아래와 같이 handleClick함수에 커링 기법을 사용하면 익명 함수를 전달해줄 필요가 없게 되어 좀 더 깔끔하게 작성이 가능하게 됩니다.
const handleClick = (value) => () => { console.log(value) };
<button onClick={handleClick(value)}>전송</button>
지금까지 커링에 대해 알아보았는데요. 언뜻 보면 어려운 개념 같지만 실제로는 아주 간단하고 함수 프로그래밍에 기초가 되는 기법이 아닐까라고 생각이 듭니다. 이 외에도 혹시 본인만의 커링 사용법 같은 게 있다면 댓글에 남겨주시길 바랍니다.
'Javascript' 카테고리의 다른 글
[JS] Promise.all과 Promise.race의 차이점과 활용 예제 (0) | 2022.04.12 |
---|---|
프론트엔드 개발자가 알아두면 유용한 JS 문법들 - 1편 (0) | 2022.03.29 |
JS 배열 요소 삭제하는 방법 (shift, pop, splice, slice, filter) (0) | 2022.03.13 |
JS 배열에 요소 추가하는 방법 (mutable, immutable) (0) | 2022.03.12 |
JS 배열 생성하는 방법 (리터럴, 생성자 함수) (0) | 2022.03.11 |