커링

HongBoogie·2025년 3월 17일
0

회사 적응을 위해 코드를 읽다가

const Loadable = Component => props => {
  const {pathname} = useLocation();

  return (
    <Suspense
      fallback={
        <LoadingScreen isDashboard={pathname.includes('/dashboard')} />
      }>
      <Component {...props} />
    </Suspense>
  );
};

const CreateVehicle = Loadable(
  lazy(() => import('src/pages/commute/mycar/CreateVehicle')),
);

이런식으로 파라미터를 나눠서 받는 형태의 함수가 보였다. 이런 형태가 커링이라는 이름을 띈다는 것은 알고 있었으나,

const Loadable = ({Component, props}) ⇒ { }; 형태와 정확히 뭐가 다르고, 왜 쓰는지를 몰랐다. 이 기회를 틈타 공부해본다!

커링이란?

이 함수는 왜 커링인가? 사실 별 뜻이 있는건 아니었다. 커링 이론을 발전시킨 인물의 이름이 하스켈 커리(Haskell Curry)이고, 이로부터 유래됐다고 한다. 프로그래밍 세계에서의 커링은

  1. 인자를 여러개 받는 함수를 분리해 인자를 하나씩만 받는 함수로 만드는 방법.
  2. 함수형 프로그래밍 기법 중 하나로, 함수를 재사용하고 리팩토링하기 쉽게 만드는 방법.

자바스크립트의 경우 커링이 따로 내장되어 있지는 않기에 필요에 따라 직접 구현하여 사용하면 된다고 한다.

실전 예제를 살펴보자.

// 커링 적용전 곱셈함수
const multiply_v1 = (a, b, c) => {
    return a * b * c;
}

// 커링 적용한 곱셈함수
const multiply_v2 = (a) => (b) => (c) => {
    return a * b * c;
}

위의 함수와 달리 아래의 함수는 커링을 통해 각각 a,b,c의 인자 하나씩 받는 함수로 변경해 사용하고 있다.

위 함수를 화살표 함수를 사용안하고 구현하면 가관인데,

function multiply_v2(a) {
    return function (b) {
        return function (c)  {
            return a * b * c
        }
    }
}

// 호출: multiple_v2(2)(3)(4) = 24

여기까지만 보면 아니, 이거 대체 왜씀 ..? 이라는 말이 절로 나온다.

하지만 커링의 진가는 함수를 호출하고 재사용할 때 진가를 발휘한다.

예제 1

예를 들어 보자. 나는 장바구니에 담긴 물건들의 가격을 계산하는 함수를 만들고 싶다.

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);

커링을 적용하지 않은 경우, VAT는 일종의 매직 넘버임에도 함수에 일일히 적용해줘야 하는 번거로움이 존재했다.

const priceWithVAT = multilply_v2(VAT);

const shirts_price = priceWithVAT(20000)(4);
const pants_price = priceWithVAT(15000)(4);

현재는 인자가 많이 필요하지 않아 이게 그렇게 실용적인가? 느낄 수 있다.

예제 2

자바스크립트는 함수도 인자로 받을 수 있다(일급 객체이므로). 정말 다양한 활용이 가능하다.

나는 방정식 4x * (x+2)를 수행할 함수를 만들고 싶다.

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

const addX = x => a => add(a, x);
const addTwo = addX(2);

const multiplyX = x => a => multiply(a, x);
const multiplyFour = multiplyX(4);

우선 이렇게 커링을 통해 addTwo, multiplyFour 함수를 만들고,

    const compose = fn => fn2 => x => fn2(x) * fn(x);
    const equation = compose(addTwo)(multiplyFour);
    equation(10) // (4 * 10) * (10 + 2) = 40 * 12 = 480
    equation(20) // (4 * 20) * (20 + 2) = 1760

이런식으로 equation이라는 함수를 통해 여러가지 값을 받는 함수를 만들 수 있다.

만약 추가사항이 생겨 5x(x+2)의 결과를 반환하는 함수가 필요하다면?

  const multiplyFive = multiplyX(5);
    const equaion2 = compose(addTwo)(multiplyFive);
    equation2(10) // (5 * 10) * (10 + 2) = 600

간단하게 수정하여 사용할 수 있다.

예제 3

커링을 통해 이벤트 핸들러를 좀 더 깔끔하게 적을 수 있다.

기존의 이벤트 핸들러는

// 인자가 없을경우
<button onClick={handleClick}>전송</button>

// 인자가 있을경우 (익명 함수로 전달)
<button onClick={() => handleClick(value)}>전송</button>

이런식으로 인자가 있는 경우 함수가 바로 호출되지 않도록 익명 함수로 전달해야 했다.

익명 함수로 전달하는 방법에 문제가 있는 것은 아니지만, handleClick 함수에 커링 기법을 사용하면 익명 함수를 전달해줄 필요가 없어 좀 더 깔끔해진다.

const handleClick = (value) => () => {console.log(value)};

<button onClick={handleClick(value)} />

지금까지 커링에 대해 알아보았다. 함수형 프로그래밍의 꽃이라고도 불리는 커링이다보니 어려워지면 정말 한없이 어려워지는데, 잘만 이용하면 재사용성 측면에서 많은 이점이 있을 것이라 느껴졌다.

HOC(고차 컴포넌트)의 구현에도 적합하니 다방면으로 활용해봐야겠다.

profile
개발이 즐겁고 노는게 즐거워요

0개의 댓글

관련 채용 정보