출처 - hustle-dev 벨로그
커링(Currying)은 함수의
재사용성을 높이기 위해 함수 자체를 return하는 함수
이다.쉽게 말하면,
'함수를 반환하는 함수'
이다.
함수를 하나만 사용할 때는 필요한 모든 파라미터를 한 번에 넣어야 한다. 커링을 사용하면 함수를 분리할 수 있으므로 파라미터도 나눠 전달할 수 있다.
고차 함수
라고 부르기도 한다.커링이 왜 사용될까??
함수의 재활용을 위해서
- 원하는 함수들을 조합해서 사용할 수 있다.
하나 이상의 인수의 함수를, 하나의 인수를 받는 함수로 축소할 수 있다.
- 그래서 더 가벼운 함수 제작이 가능하다.
function add(a,b){
return a+b;
}
다음 add 함수를 재활용 하려면?
function addTwo(a){
return add(a,2)
}
이렇게 2+@를 해주는 addTwo 함수를 만들 수 있다.
만약 add3, add4, add5... 등의 여러 함수가 필요하다고 하자.
function addTwo(a){
return add(a,2);
}
function addThree(a){
return add(a,3);
}
function addFour(a){
return add(a,4);
}
분명 add 함수를 재활용하긴 하지만, 뭔가 이상하다.
여기에 커링을 적용해보자.
function add(a,b){
return console.log(a+b);
}
function addX(x){
return function(a){
return add(a, x);
}
}
const addTwo = addX(2);
const addThree = addX(3);
const addFour = addX(4);
addTwo(2); // 2 + 2 = 4
addThree(5); // 3 + 5 = 8
addFour(1); // 4 + 1 = 5
다음과 같이 addX 함수를 이용해서 여러 파생 함수들을 만들 수 있다.
addX 함수는 이렇게 동작한다.
인자 x를 받아서 익명함수를 반환한다. 그 함수는 function(a){ return add(a,x); } 의 형태이다.
반환받은 값인 함수는 인자 a를 요구한다. a를 넣어주면 add(a,x)의 실행 결과를 반환한다.
이처럼 함수 실행을 위한 인자를 한 번에 받지 않고, 여러 차례에 나눠서 받을 수 있다.
이 예시를 화살표 함수로 나타내면,
function addX(x){
return function(a){
return add(a, x);
}
}
const addX = x => a => add(a,x);
이렇게 더 간단해진다.
자바스크립트에서는 함수도 값이다.
그러므로 함수의 인자로 또 다른 함수도 받을 수 있다.
function curry(fn){
return function(a){
return function(b){
return fn(a,b);
}
}
}
이제 이 함수를 어떻게 써야할까?
정확히 위에서 선언했던 addX와 동일하게 만들 수 있다.
function add(a,b){
return a+b;
}
const addX = curry(add);
const addTwo = addX(2);
console.log(addTwo(5));
함수 자체를 인자로 받아서 활용할 수 있는 것을 알게 되면, 코드를 작성하는 스타일이 더 다양해진다.
커링을 사용하지 않은 경우 :
const todos = [
{ id: 3, content: 'HTML', completed: false },
{ id: 2, content: 'CSS', completed: true },
{ id: 1, content: 'Javascript', completed: false}
];
const getTodosIdArr = todos => todos.map(todo => todo.id);
const getTodosContentArr = todos => todos.map(todo => todo.content);
const getTodosCompletedArr = todos => todos.map(todo => todo.completed)
console.log(getTodosIdArr(todos)); // [ 3, 2, 1 ]
console.log(getTodosContentArr(todos)); // [ 'HTML', 'CSS', 'Javascript' ]
console.log(getTodosCompletedArr(todos)); // [ false, true, false ]
일반적인 경우 코드를 작성하면 위와 같이 작성하게 된다. 여기에 커링을 적용해보자.
커링을 사용한 경우 :
const todos = [
{ id: 3, content: 'HTML', completed: false },
{ id: 2, content: 'CSS', completed: true },
{ id: 1, content: 'Javascript', completed: false }
];
const get = property => object => object[property];
const getId = get('id'); // object => object['id'];
const getContent = get('content'); // object => object['content'];
const getCompleted = get('completed'); // object => object['completed']
const getTodosIdArr = todos => todos.map(getId);
const getTodosContentArr = todos => todos.map(getContent);
const getTodosCompletedArr = todos => todos.map(getCompleted);
console.log(getTodosIdArr(todos)); // [ 3, 2, 1 ]
console.log(getTodosContentArr(todos)); // [ 'HTML', 'CSS', 'Javascript' ]
console.log(getTodosCompletedArr(todos)); // [ false, true, false ]
커링을 사용하는 경우 인자의 순서가 중요하다.
앞에 존재하는 인자일 수록 변동 가능성이 적고, 뒤에 있는 인자일 수록 변동 가능성이 높기 때문에 이 순서를 고려하여 설계하는 것이 중요하다고 한다.
function 키워드 없이 화살표 함수로 표현하여 방정식 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 함수에 넣는 값이 x가 되어 4x(x+2)의 다양한 값에 대한 결과를 받을 수 있다.
만약 5x(x+2)의 결과를 반환하는 함수가 필요하다면?
const multiplyFive = multiplyX(5);
const equaion2 = compose(addTwo)(multiplyFive);
equation2(10) // (5 * 10) * (10 + 2) = 600
이렇게 표현할 수 있다.
마지막으로 위에서 선언한 equation 함수를 생성하면서 중복되는 부분을 제거하면,
const addTwo = addX(2);
const addFour = addX(4);
const multiplyFour = multiplyX(4);
const multiplyFive = multiplyX(5);
const compose = fn => fn2 => x => fn2(x) * fn(x);
const composeAddTwo = compose(addTwo);
const equation1 = composeAddTwo(multiplyFour); // 4x(x+2)
const equation2 = composeAddTwo(multiplyFive); // 5x(x+2)
const equation3 = composeAddTwo(addFour) // (x+4)(x+2)
위와 같이 인자로 받은 함수들을 교체해주면서, 유사한 함수들을 여러개 만들 수 있다.
참고 - Go devlog, hustle-dev velog