자바스크립트의 비밀스러운 삶: 커링 vs. 부분 적용
Source: Dev.to
실용적인 접근법: 부분 적용 (Partial Application)
// A standard, multi‑argument function
function multiply(a, b) {
return a * b;
}
// Manually creating partial application via a closure factory
function createMultiplier(factor) {
// We "lock in" the 'factor' argument here
return function (number) {
return number * factor;
};
}
// Usage
const double = createMultiplier(2); // We applied '2' to the first spot
console.log(double(10)); // 20
Partial Application은 수동 기법입니다: 일반 함수의 일부 인자를 미리 채워 새로운 함수를 만들고, 남은 인자를 기다리게 합니다.
Original Function: [ Slot A ] [ Slot B ] [ Slot C ]
Partial Application:
We choose to fill Slot A now.
Resulting Function: [ 10 ] [ Slot B ] [ Slot C ]
구조적인 접근법: 커링 (Currying)
커링은 함수 시그니처의 구조적 변환입니다. 다중 인자 함수를 일련의 단일 인자 함수 체인으로 바꿉니다.
const formatUrl = protocol => domain => path => `${protocol}://${domain}/${path}`;
// Partial Application – manual process
// We can fill any arguments we want, in any order we design
const addFive = (b, c) => add(5, b, c);
// Currying – structural transformation
// It forces a rigid chain: one arg at a time
const curriedAdd = a => b => c => a + b + c;
// You MUST call it like this:
curriedAdd(1)(2)(3);
체인을 깨려고 하면 실패합니다:
// This won't work as expected with a truly curried function:
// It returns a function expecting 'path', it does NOT use 'myblog.com' as the domain yet!
formatUrl('https', 'myblog.com');
비유: 샌드위치 메이커 vs. 조립 라인
부분 적용 샌드위치 메이커
일반적인 샌드위치 레시피에 빵, 고기, 치즈가 필요합니다. 오늘 사용할 빵이 사워도우라는 것을 안다면, 미리 사워도우 조각을 준비해 둡니다. 이렇게 빵 인자를 수동으로 “부분 적용”하면 이후 단계가 빨라집니다.
커리된 조립 라인
세 개의 스테이션을 가진 산업용 샌드위치 공장 로봇을 상상해 보세요:
- 스테이션 1 – 빵만 받으며 결과를 스테이션 2에 전달합니다.
- 스테이션 2 – 고기만 받으며 결과를 스테이션 3에 전달합니다.
- 스테이션 3 – 치즈만 받습니다.
빵과 고기를 동시에 스테이션 1에 넣을 수 없습니다; 조립 라인은 한 번에 하나의 인자만 흐르게 강제합니다.
라이브러리가 커링을 사용한 이유
커링을 사용하면 특화된 빌더를 쉽게 만들 수 있기 때문입니다:
// Create a builder specifically for secure sites
const secureUrl = formatUrl('https');
// Create a builder specifically for OUR site
const myBlogUrl = secureUrl('myblog.com');
// Generating links is clean:
const post1 = myBlogUrl('post-1');
const post2 = myBlogUrl('post-2');
커리된 formatUrl은 조립 라인의 어느 단계에서든 멈출 수 있게 해 주어, 새로운 정의 없이 재사용 가능한 부분 함수를 생성합니다.
흔한 함정: 혼합 패턴
// Not truly curried (breaks the single‑argument chain)
const add = a => (b, c) => a + b + c; // returns a function taking TWO args
// Truly curried (maintains single‑argument chain)
const curriedAdd = a => b => c => a + b + c; // each returns a function taking ONE arg
첫 번째 예시는 하이브리드이며, 진정한 커링은 함수당 하나의 인자만 받는 패턴을 끝까지 유지합니다.
Margaret’s Cheat Sheet
부분 적용을 사용할 때:
- 표준 JavaScript를 작성할 때.
- 특정 사용 사례에 맞게 함수를 특화할 때 (예:
createMultiplier). - 유연성이 필요할 때 (예: 첫 번째 및 세 번째 인자를 고정하고 두 번째는 열어두는 경우).
커링을 사용할 때:
- 함수형 라이브러리를 사용할 때 (예: Ramda, Lodash/fp).
- 최대한의 합성을 원할 때 (데이터를 체인으로 파이프할 때).
- 함수의 다양한 특화 버전을 자동으로 생성하고 싶을 때.
일상적인 JavaScript에서는 부분 적용이 자주 등장하지만, 진정한 커링은 드뭅니다—하지만 두 개념의 차이를 이해하면 상황에 맞는 도구를 선택하는 데 도움이 됩니다.