JadeCode

[리뷰] 고차함수 본문

개발/웹

[리뷰] 고차함수

z-zero 2022. 5. 24. 20:00

일급 객체

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

JS의 일급 객체 중 하나가 함수이다.

1. 변수에 함수를 할당할 수 있다.

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

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

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

고차함수

고차 함수는 함수를 전달인자로 받을 수 있고, 함수를 리턴할 수 있는 함수이다. 

 

다른 함수(caller)의 전달인자(argument)로 전달되는 함수를 콜백 함수(callback function)라고 한다.

어떤 작업이 완료되었을 때 호출하는 경우가 많아서, 답신 전화를 뜻하는 콜백 함수라는 이름이 붙여졌다.

 

콜백함수를 전달받은 고차 함수는 함수 내부에서 이 콜백 함수를 호출할 수 있고, 조건에 따라 콜백 함수의 실행 여부를 결정할 수도 있다. 

 

'함수를 리턴하는 함수'는 모양새가 특이한 만큼, 부르는 용어가 따로 있다. '함수를 리턴하는 함수'를 고안해 낸 논리학자 하스켈 커리(Haskell Curry)의 이름을 따, 커링 함수라고 한다. 따로 커링 함수라는 용어를 사용하는 경우에는, 고차 함수라는 용어를 '함수를 전달인자로 받는 함수'에만 한정해 사용하기도 한다.

그러나 정확하게 구분하자면, 고차 함수가 커링 함수를 포함한다.

 

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

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

function doubleNum(func, num) { //다른 함수를 인자로 받는 고차함수
  return func(num);
  /*함수 func는 함수 doubleNum의 콜백 함수다.*/
}

let output = doubleNum(double, 4);
/* 함수 double은 함수 doubleNum의 콜백함수다*/
console.log(output); // -> 8

2. 함수를 리턴하는 경우

function adder(added) {
  /* 함수 adder는 다른 함수를 리턴하는 고차 함수 */
  /* adder는 인자 한 개를 입력받아서 함수(익명 함수)를 리턴한다. */
  return function (num) {
    return num + added;
    /* 리턴되는 익명 함수는 인자 한 개를 받아서 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;
  };
}

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

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

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

고차함수는 함수를 전달인자로 받는 함수, 함수를 리턴하는 함수이다.

함수의 전달인자로 전달되는 함수를 콜백함수라 한다.


 

내장 고차 함수(filter,map,reduce)

  • filter, map, reduce, forEach, find, sort, some, every

모든 요소 중 내가 원하는 값만 필터링하여 반환한다.

 

filter : 함수를 전달인자로 받아서 고차함수

배열의 각 요소가 특정 논리(함수)에 따르면, 사실(true)일 때 따로 분류한다.

조건에 맞는 데이터만 분류할 때 사용한다.

const isOdd = function (num) {
  return num % 2 === 1;
};

let arr = [1, 2, 3, 4, 5, 6, 7];
let output = arr.filter(isOdd);
console.log(output); // ->> ?

/* 화살표 함수로 나타내기 */
let oddList = arr.filter((num)=>num % 2 === 1)

map

배열의 각 요소가 특정 논리(함수)에 의해 다른 요소로 지정(map)된다.

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

let arr = [1, 2, 3, 4, 5, 6, 7];
let output = arr.map(double);
console.log(output); // ->> [2,4,6,8,10,12,14]

reduce 

배열의 각 요소를 특정 방법(함수)에 따라 원하는 하나의 형태로 응축한다. (reduction)

리듀스는 초기값을 정할 수 있는데 정하지 않는다면 배열의 제일 첫번째 인자가 초기값이 된다. 초기값은 누적값의 기반이 된다. 이 둘은 우리가 더하는 배열의 결국에 누적값의 값을 반환하게 된다.

 

누적값(acc)과 현재값(cur)을 더하는 함수가 reduce 메서드의 첫번째 전달인자로 전달되었고, 초기값(initialValue) 1이 두번째 전달인자로 전달되었다. 따라서, 첫 누적값(acc)은 초기값(initialValue) 1이 된다.
따라서 초기값 1에 arr 배열의 요소인 1부터 7까지의 수를 누적하여 더한 값인 29가 출력된다.

고차함수를 써야하는 이유

추상화 = 생산성의 향상

복잡한 어떤 것을 압축해서 핵심만 추출한 상태로 만드는 것이 추상화이다.

 

프로그램을 작성할 때, 자주 반복해서 사용하는 로직은 별도의 함수로 작성하기도 한다.

이 역시 추상화의 좋은 사례다.

 

추상화의 관점에서 함수를 바라보면, 함수는 사고(thought)또는 논리(logic)의 묶음이다.

함수를 통해 얻은 추상화를, 한 단계 더 높인 것이 고차 함수이다.

  • 함수 = 값을 전달받아 값을 리턴한다 = 값에 대한 복잡한 로직은 감추어져 있다 = 값 수준에서의 추상화

고차 함수는 이 추상화의 수준을 사고의 추상화 수준으로 끌어올립니다.

  • 값 수준의 추상화: 단순히 값(value)을 전달받아 처리하는 수준
  • 사고의 추상화: 함수(사고의 묶음)를 전달받아 처리하는 수준

다시 말해 고차 함수를 통해, 보다 높은 수준(higher order)에서 생각할 수 있다.

  • 고차 함수 = 함수를 전달받거나 함수를 리턴한다 = 사고(함수)에 대한 복잡한 로직은 감추어져 있다 = 사고 수준에서의 추상화

추상화의 수준이 높아지는 만큼, 생산성도 비약적으로 상승한다.

 

'개발 > ' 카테고리의 다른 글

[리뷰] 프로토타입  (0) 2022.05.27
[리뷰] 객체 지향 프로그래밍  (0) 2022.05.26
[리뷰] Section1 회고  (0) 2022.05.23
[리뷰] DOM  (0) 2022.05.23
[리뷰] spread, rest, 구조분해할당  (0) 2022.05.13
Comments