개발 R.I.P.

6.06 Dev.Feedback ( 일급 객체, 고차 함수 개념)

편행 2021. 6. 6. 14:17
반응형

일급 객체

자바스크립트 내에선 특별한 대우를 받는 일급 객체가 있는데, 바로 함수이다.

왜 특별한 대우를 받는다고 표현할까?

 

  • 변수에 할당(assignment) 할 수 있다.
  • 다른 함수의 인자(argument)로 전달될 수 있다.
  • 다른 함수의 결과로서 리턴될 수 있다.

 

위의 세가지 이유때문이다. 근데 이 세가지 중 가장 중요한 포인트는 바로

변수에 할당 할 수 있다.

함수를 변수에 할당할 수 있다는 것은 함수 자체를 배열의 요소나 객체의 속성값으로 저장할 수 있다는 것인데, 이는 함수를 데이터(string, number, boolean, array, object)를 다루듯이 다룰 수 있다는 걸 의미한다.

즉 위의 이유때문에 다른 함수의 인자로 전달될 수도 있는 것이고, 다른 함수의 결과로서 리턴될 수도 있는 것이다.

 

함수를 변수에 할당하는 것은 이전에 다뤄봤다.

함수 표현식

/*
 * 아래는 변수 square에 함수를 할당하는 함수 표현식
 * 자바스크립트에서 함수는 일급 객체이기 때문에 변수에 저장할 수 있다.
 *
 * 함수 표현식은 할당 전에 사용할 수 없다.
 * square(7); // --> ReferenceError: Can't find variable: square
 */

const square = function (num) {
  return num * num;
};

// square에는 함수가 저장되어 있으므로 (일급 객체), 함수 호출 연산자 '()'를 사용할 수 있다.
output = square(7);
console.log(output); // --> 49

앞서 호이스팅 관련해서 다뤘는데, 함수 표현식(함수를 변수에 할당해주는 방식)은 함수 선언식과는 다르게 호이스팅의 영향을 받지 않는다.

 

함수 선언식은 호이스팅이 적용이 되기 때문에 어느 위치에나 함수를 선언할 수 있다는 장점이 있지만 코드 리뷰나 디버깅을 할 때, 코드를 위아래로 왔다 갔다 하게 되기 때문에 코드의 유지 보수가 쉽지 않아 진다. 그렇기 때문에 함수 선언식의 호이스팅에 지나치게 의존하지 않는 것이 좋다.

 

반면에 함수 표현식은 함수의 할당과 실행의 위치에 따라 결과가 달라지기 때문에, 코드의 위치를 어느 정도 예측할 수 있어 코드의 유지 보수가 비교적 쉽다는 장점이 있다. 호이스팅을 제외하면, 함수 선언식과 함수 표현식은 크게 차이가 없다. 다만, 함수 표현식의 경우는 함수가 변수에 저장될 수 있다는 사실을 보다 분명하게 보여준다.

고차 함수란

고차 함수(higher order function)는 함수를 인자(argument)로 받을 수 있고, 함수의 형태로 리턴할 수 있는 함수이다.

 

이때 다른 함수(caller)의 인자(argument)로 전달되는 함수를 콜백 함수(callback function)라고 하는데, 콜백 함수의 이름은, 어떤 작업이 완료되었을 때 호출하는 경우가 많아서, 답신 전화를 뜻하는 콜백이라는 이름이 붙여졌다고 한다.

 

콜백 함수를 전달받은 고차 함수는, 함수 내부에서 이 콜백 함수를 호출(invoke) 할 수 있다. caller는 조건에 따라 콜백 함수의 실행 여부를 결정할 수 있는데, 아예 호출하지 않을 수도 있고, 여러 번 실행할 수도 있다.

 

'함수를 리턴하는 함수'논리학자 하스켈 커리(Haskell Curry)의 이름을 따, 커리 함수라고도 하는데, '함수를 인자로 받는 함수'에만 한정해 사용하기도 한다.

 

근데 엄연하게 따져보면, 고차 함수가 더 상위 개념이기에 굳이 나눠서 얘기를 하지 않아도 된다.

 

대표적인 고차함수의 경우

 

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

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

function doubleNum(func, num) {
  return func(num);
}

/*
 * 함수 doubleNum은 다른 함수를 인자로 받는 고차 함수
 * 함수 doubleNum의 첫 번째 인자 func에 함수가 들어올 경우
 * 함수 func는 함수 doubleNum의 콜백 함수이다.
 * 아래와 같은 경우, 함수 double은 함수 doubleNum의 콜백 함수이다.
 */
let output = doubleNum(double, 4);
return double(4)
console.log(output); // -> 8

 

2. 함수를 리턴하는 경우

function adder(added) {
  return function (num) {
    return num + added;
  };
}

/*
 * 함수 adder는 다른 함수를 리턴하는 고차 함수
 * adder는 인자 한 개를 입력받아서 함수(익명 함수)를 리턴한다.
 * 리턴되는 익명 함수는 인자 한 개를 받아서 added와 더한 값을 리턴한다.
 */

// adder(5)는 함수이므로 함수 호출 연산자 '()'를 사용할 수 있다.
let output = adder(5)(3); // -> 8
console.log(output); // -> 8

// adder가 리턴하는 함수를 변수에 저장할 수 있다. (함수 표현식)
// javascript에서 함수는 일급 객체이기 때문
const add3 = adder(3);
output = add3(2);
console.log(output); // -> 5

 

3. 함수를 인자로 받고, 함수를 리턴하는 경우

 

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

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

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

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

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

'개발 R.I.P.' 카테고리의 다른 글

6.08 Dev.Feedback (React #2 SPA, Router)  (0) 2021.06.08
6.07 Dev.Feedback(Array filter, map, reduce)  (0) 2021.06.07
6.05 Dev.Feedback (이벤트 정리)  (0) 2021.06.05
6.04 Dev.Feedback (React #1)  (0) 2021.06.04
6.03 Dev.Feedback(DOM)  (0) 2021.06.03