고차 함수란


고차 함수(higher order function)는 함수를 인자(argument)로 받거나 함수를 리턴하는 함수를 말합니다. 이 때 다른 함수(caller)의 인자(argument)로 전달되는 함수를 콜백 함수(callback function)라고 합니다.

콜백 함수를 전달받은 함수는 이 콜백 함수를 호출(invoke)할 수 있습니다. caller는 조건에 따라 콜백 함수의 실행 여부를 결정할 수도 있고, 심지어 여러 번 실행할 수도 있습니다. 특히 콜백 함수는 어떤 작업이 완료되었을 때 호출되는 경우가 많아서 답신 전화를 뜻하는 콜백이라는 이름이 붙여졌습니다.

한편, '함수를 리턴하는 함수'만을 일컫는 용어가 따로 존재하고 실제로도 많이 쓰입니다. 이런 함수를 이를 고안해 낸 논리학자 하스켈 커리(Haskell Curry)의 이름을 따라 커리 함수라고 합니다. 따로 커리 함수라는 용어를 사용하는 경우, 고차 함수란 용어를 '함수를 인자로 받는 함수'에만 한정지어서 사용하기도 합니다. 하지만 엄밀한 의미에서 고차 함수는 커리 함수를 포함합니다.

  1. 다른 함수를 인자로 받는 경우

    function double(num) {
      return num * 2;
    }
    
    function doubleNum(func, num) {
      let doubledArr = [];
      return func(num);
    }
    
    // 함수 doubleNum은 다른 함수를 인자로 받는 고차 함수입니다.
    // 함수 doubleNum의 첫 번째 인자 func에 함수가 들어올 경우
    // 함수 func는 함수 doubleNum의 콜백 함수입니다.
    // 아래와 같은 경우, 함수 double은 함수 doubleNum의 콜백 함수입니다.
    let output = doubleNum(double, 4);
    console.log(output); // -> 8
    
  2. 함수를 리턴하는 경우

function double(num) {
  return num * 2;
}

~~~~function doubleAdder(added, func) {
  const doubled = func(added);
  return function (num) {
    return num + doubled;
  };
}

// 함수 doubleAdder는 고차 함수입니다.
// 함수 doubleAdder의 인자 func는 함수 doubleAdder의 콜백 함수 입니다.
// 함수 double은 함수 doubleAdder의 콜백으로 전달되었습니다.

// doubleAdder(5, double)는 함수이므로 함수 호출 기호 '()'를 사용할 수 있습니다.
doubleAdder(5, double)(3); // -> 13

// doubleAdder가 리턴하는 함수를 변수에 저장할 수 있습니다. (일급 객체)
const addTwice3 = doubleAdder(3, double);
addTwice3(2); // --> 8
  1. 함수를 인자로 받고, 함수를 리턴하는 경우
function double(num) {
  return num * 2;
}

function doubleAdder(added, func) {
  const doubled = func(added);
  return function (num) {
    return num + doubled;
  };
}

// 함수 doubleAdder는 고차 함수입니다.
// 함수 doubleAdder의 인자 func는 함수 doubleAdder의 콜백 함수 입니다.
// 함수 double은 함수 doubleAdder의 콜백으로 전달되었습니다.

// doubleAdder(5, double)는 함수이므로 함수 호출 기호 '()'를 사용할 수 있습니다.
doubleAdder(5, double)(3); // -> 13

// doubleAdder가 리턴하는 함수를 변수에 저장할 수 있습니다. (일급 객체)
const addTwice3 = doubleAdder(3, double);
addTwice3(2); // --> 8