함수에 함수 전달
함수에 함수를 전달하는 예제는 setTimeout과 forEach에서 이미 봤습니다. 함수에 함수를 전달하는 다른 용도는 비동기적 프로그래밍입니다. 이런 용도로 전달하는 함수를 보통 콜백callback이라 부르며, 약자로 cb를 쓸 때가 많습니다. 콜백 함수는 자신을 감싼 함수가 실행을 마쳤을 때 호출됩니다. 콜백은 14장에서 자세히 설명합니다.
함수에 함수를 전달하는 대표적인 사례가 콜백이긴 하지만, 그게 전부는 아닙니다. 함수는 동작이고, 함수를 받은 함수는 그 동작을 활용할 수 있습니다. 배열에 들어있는 숫자를 모두 더하는 단순한 함수 sum이 필요하다고 합시다(배열에 숫자가 아닌 것이 들어있을 때를 대비한 체크나 에러 처리는 생략하겠습니다). 그런 함수는 쉽게 만들 수 있습니다. 그런데 숫자의 제곱square을 합해서 반환하는 함수가 필요하다면? 물론 새 함수 sumOfSquares를 만들어도 됩니다. 그런데, 세제곱을 합해서 반환하는 함수도 필요하다면? 이런 상황에서 함수에 함수를 전달한다는 발상이 필요합니다. sum을 이렇게 만들었다고 합시다.
function sum(arr, f) {
//함수가 전달되지 않았으면 매개변수 그대로를 반환하는 null 함수를 씁니다.
if(typeof f != 'function') f = x => x;
return arr.reduce((a, x) => a += f(x), 0);
}
sum([1,2,3]); //6
sum([1,2,3], x => x*x); //14
sum([1,2,3], x => Math.pow(x,3)); //36
임의의 함수를 sum에 전달하면 원하는 일을 거의 모두 할 수 있습니다. 제곱근의 합이 필요한가요? 아무 문제도 없습니다. 숫자의 4.233 제곱의 합이 필요한가요? 바로 할 수 있습니다. sum을 바로, 즉 함수를 넘기지 않고 호출해야 할 수도 있습니다. 함수를 넘기지 않고 sum을 호출하면 매개변수 f의 값은 undefined이므로 에러가 일어납니다. 에러를 방지하기 위해 함수가 아닌 것은 모두 ‘null 함수’, 즉 아무 일도 하지 않는 것으로 바꿉니다. 즉 null 함수 f에 5를 넘기면 그대로 5를 반환합니다. 배열의 모든 요소에서 null 함수를 호출하는 것보다는 요소를 그냥 더하는 함수를 한 번 호출하는 등 더 효율적인 방법이 물론 있겠지만, 이런 식으로 ‘안전한’ 함수를 만들 수 있다는 걸 충분히 이해했을 겁니다.