저번 좋은 성능과 가독성을 위한 if-else문에 대해 포스팅 하던 중 일급 객체에 대해서 설명을 한 부분이 있는데, 모든 일급 객체에는 다른 함수의 리턴값으로 사용할 수 있어야한다는 부분이 있었다. 자바스크립트에서는 커링을 통해 함수의 리턴값을 호출할 수 있었는데, 그럼 커링이 뭐길래 그게 가능한건지 알아보기로 하였다.
커링이라는 단어는 사실 어디서 많이 주워듣긴 했었다. 하지만 정확한 정의와 왜 사용하는지를 정확하게 알지 못해서 이번 기회에 제대로 알아보고 정리를 해보려고한다.
커링(Currying)이란
커링은 함수의 재사용성을 높히고, 더 가벼운 함수 제작을 위해 함수 자체를 return하는 함수를 말한다. 즉, 여러개의 매개변수를 갖는 함수를 부분적으로 나누어서 각각 단일 매개변수를 갖는 함수로 만든 함수이다.
보통 함수 하나를 사용할 때는 그 함수에 필요한 모든 매개변수를 한번에 넣어주고 사용한다.
// 일반적인 함수
const add = (num1, num2) => {
console.log(num1 + num2);
};
add(1, 2); // 3
위의 add 함수를 재사용하여 다양한 파생함수를 만들어본다고 가정해보자.
// 일반적인 함수 재사용
const add = (num1, num2) => {
return num1 + num2;
};
const addTwo = (num1) => {
console.log(add(2, num1));
};
addTwo(3); // 5
const addThree = (num1) => {
console.log(add(3, num1));
};
addThree(3); // 6
const addFour = (num1) => {
console.log(add(4, num1));
};
addFour(3); // 7
뭐 이런식으로 재사용할 수 있을 것이다. 재사용을 하긴하지만 재사용할때의 편리함을 전혀 느낄 수 없다.
이걸 커링을 통해 바꿔보자.
// 커링 함수를 통한 재사용
const add = (num1, num2) => {
return num1 + num2;
};
const addNum = (num1) => {
return (num2) => {
console.log(add(num1, num2));
};
};
const addTwo = addNum(2);
const addThree = addNum(3);
const addFour = addNum(4);
addTwo(3); // 5
addThree(3); // 6
addFour(3); // 7
커링을 사용하지 않고 사용할 때처럼 결과값을 바로 반환하는게 아닌 새로운 매개변수 num2를 받아서 순차적으로 익명함수를 반환하는식으로 동작한다. 순차적이라는 것을 좀더 확실하게 알기위해 매개변수를 3개로 늘려보면,
const add = (num1, num2, num3) => {
return num1 + num2 + num3;
};
const addNum = (num1) => {
return (num2) => {
return (num3) => {
console.log(add(num1, num2, num3));
};
};
};
const addTwo = addNum(2);
const addThree = addNum(3);
const addFour = addNum(4);
addTwo(3)(4); // 9
addThree(3)(4); // 10
addFour(3)(4); // 11
해당 코드처럼 순차적으로 num2, num3인 3, 4를 순차적으로 반환받아서 가장 내부에 있는 함수가 반환되어 호출되었을 때 세개의 매개변수를 더한 값을 반환하게 된다. 하지만, 가독성이 일반적인 함수보다 떨어져보인다. 그럼 비교적 떨어지는 가독성을 포기하면서까지 커링함수를 왜 사용할까를 생각해보면 그만큼 재사용성에서 뛰어나기 떄문에 사용한다. 그럼 이걸 어느곳에서 응용할 수 있을까?
어떤 물건들을 구매하려고 할 때 물건들의 가격을 출력할 때의 상황을 생각해보자. 일반적인 함수로는 아래처럼 받아서 출력할 수 있을 것이다.
const VAT = 1.05; // 부가세 5%
const calculate = (a, b, c) => {
return a * b * c;
};
const clothes_prices = calculate(VAT, 20000, 3); // 63000
const books_prices = calculate(VAT, 12000, 4); // 50400
부가세인 VAT는 물건의 값이 얼마, 몇개를 사던 고정값임에도 계산을 위해 매번 전달해줘야한다. 하지만, 고정값인 부가세는 매번 매개변수로 전달해주지 않고 사용할 수 있다. 커링함수를 사용하여 출력해보자.
const VAT = 1.05; // 부가세 5%
const calculate = (VAT) => {
return (b) => {
return (c) => {
return VAT * b * c;
};
};
};
const calculated_VAT = calculate(VAT);
const clothes_prices = calculated_VAT(20000)(3); // 63000
const books_prices = calculated_VAT(12000)(4); // 50400
위처럼 고정값은 VAT가 첫번째 매개변수로 전달된 calculated_VAT 함수에 가격과 수량만 매개변수로 순차적으로 넣어줌으로써 재사용성을 높힐 수 있다. 위의 예제로만 보면, 솔직하게 커링함수 사용에 대한 이유를 모르겠고 오히려 가독성을 해친다고 생각된다. 하지만, 함수가 좀더 복잡하거나 매개변수가 많아지게 될 때 커링함수에게 도움을 많이 받을 수 있을 것이다. 매개변수가 많아지는 함수를 사용할 일이 생길 때 커링을 적용해보는 것을 목표로 해보고, 오늘은 커링함수가 정확히 무엇이고 무엇을 위해 사용하는지에 대해서 알아보았다.