고차함수

moono·2023년 1월 13일
0

JavaScript

목록 보기
17/23

일급 객체

대표적인 일급 객체(Javascript 에서 특별 대우 받음) 중 하나가 함수

  • 변수에 할당 가능
  • 다른 함수의 전달인자 로 전달 가능
  • 다른 함수의 결과로 리턴 가능

⇒ 함수를 변수에 할당할 수 있기 때문에 배열의 요소나 객체의 속성값으로 저장 가능하고
데이터(string, number, boolean, array, object)처럼 다룰 수 있다.

// 함수표현식
const square = function(num) {
  return num * num
}

output = square(7);
console.log(output) // 49 -> 7*7


고차 함수

고차함수는 함수를 전달인자로 받거나 함수를 리턴하는 함수

  • 콜백 함수 : 다른 함수의 전달인자로 전달되는 함수
    ⇒ 어떤 작업이 완료되었을 때 호출되는 경우가 많음

  • 커링 함수 : 함수를 리턴하는 함수
    새로운 기능을 하는 함수를 만든다.

  • 고차 함수 : 따로 커링 함수라고 표현하는 경우 함수를 전달인자로 받는 함수라고 한정해 사용하기도 하지만 정확히 구분하면 커링 함수는 고차 함수에 포함됨

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

함수 doubleNum은 다른 함수를 인자로 받는 고차 함수
함수 doubleNum의 첫번째 인자 func에 함수가 들어올 경우 func는 doubleNum의 콜백 함수
⇒ 함수 double 은 함수 doubleNum 의 콜백 함수

function double(num) {
  return num * 2
}

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

let output = doubleNum(double, 4);
console.log(output); // 8

함수를 리턴하는 경우

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

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

// adder(5)는 함수니까 함수 호출 기호'()' 를 사용 가능
let output = adder(5)(3); // 8
console.log(output); // 8

// 함수는 일급 객체기 때문에 adder가 리턴하는 함수를 변수에 저장할 수 있음
const add3 = adder(3);
output = add3(2); // adder(3)(2) 라는 뜻
console.log(output); // 5

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

함수 doubleAdder는 고차 함수
doubleAdder의 인자 func는 doubleAdder의 콜백 함수
함수 double은 doubleAdder의 콜백으로 전달

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

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

// doubleAdder(5, double)는 함수니까 함수 호출 기호'()' 를 사용 가능
doubleAdder(5, double)(3) // 13

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


내장 고차 함수

Javascript에는 기본적으로 내장된 고차 함수가 있는데
대표적인 내장 고차 함수로는 filter, map, reduce 등이 있다.

filter()

  • 판별 함수(조건)을 만족하는 참인 요소만 모아 새로운 배열로 반환
  • 필수인자 : 실행할 함수(콜백 함수)
    ⇒ 현재 요소(값)을 가지며, 선택적으로 현재요소의 인덱스와 filter() 호출한 배열을 가질 수 있음
  • 판별 함수의 테스트 통과된 요소가 없다면 빈배열 반환
const arr = [10, 100, 40, 20, 254, 123, 33];
const fArr = arr.filter((a) => a > 99) // [100, 254, 123]

map()

  • 배열의 모든 요소들에 각각 주어진 함수를 실행한 뒤 결과들을 모아 새로운 배열로 반환
    ⇒ 하나의 데이터를 다른 데이터로 맵핑할 때 사용
  • 필수인자 : 실행할 함수(콜백 함수)
    ⇒ 현재 요소(값)을 가지며, 선택적으로 현재요소의 인덱스와 map()을 호출한 배열을 가질 수 있음
  • forEach() 와 동일한 종류의 인자를 가지고 거의 동일하게 동작하지만 forEach() 는 반환값이 없다.
const arr = [1, 2, 3, 4, 5];
const mArr = arr.map((a) => a * 5) // [5, 10, 15, 20, 25]

reduce()

  • el.reduce((a,b) => a+b, 0)
    ⇒ a는 실행한 함수의 결과를 계속 누적하고 a의 값을 리턴
    ⇒ b는 el 에 있는 요소들을 하나씩 대입
  • 배열의 각 요소에 주어진 리듀서 함수를 실행하고 결과값을 반환
  • 필수인자 : 리듀서 함수(콜백 함수) + 초기실행값은 선택(안쓰면 default 0)
const arr = [1, 2, 3, 4];
//reduce로 만들기
arr.reduce((a,b) => {
  if(b > 3) return a + b * 2; // arr의 요소 중 3보다 큰 애만 * 2
  return a;
},0) // 8

*****
//filter, map, reduce 로 만들기
arr.filter(a => a>3).map(a => a*2).reduce((a,b) => a + b) // 8


고차함수 쓰는 이유

복잡한 어떤 것을 압축해서 핵심만 추출한 상태로 만드는 것을 뜻하는 용어는 추상화인데,
자바스크립트를 비롯한 많은 프로그래밍 언어 역시 추상화의 결과
어떤 과정을 거쳐서 결과가 출력되는지 몰라도 결과를 출력할 수 있다.
⇒ 추상화 : 생산성의 향상!!

고차 함수는 함수를 전달인자로 전달받기 때문에, 사고(thought) 수준에서의 추상화로 볼 수 있습니다.

추상화의 좋은 사례

프로그램을 작성할 때 자주 반복해서 사용하는 로직은 별도의 함수로 작성
추상화의 관점에서 보면 함수는 사고 또는 논리의 묶음

function getAverage(data) {
  let sum = 0;
  for (let i = 0; i < data.length; i++) {
    sum = sum + data[i]
  }
  return sum / data.length;
}

let output = getAverage([1, 2, 3]);
console.log(output); // 2 // (6/3)

output = getAverage([4, 2, 3, 6, 5, 4])
console.log(output); // 4 // (24/6)

⇒ getAverage 함수는 단순히 값(배열)을 전달인자로 전달받아, 이 값을 가지고 복잡한 작업을 수행 -> 이는 값(value) 수준에서의 추상화

  • 함수 = 값을 전달받아 값 리턴 = 값의 복잡한 로직 감춰져 있음 = 값 수준의 추상화

⇒ 고차 함수는 이 추상화의 수준을 사고의 추상화 수준으로 끌어올림

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

함수를 통해 얻은 추상화를 한단계 더 높이는 것이 고차함수

⇒ 고차함수 통해 보다 높은 수준에서 생각 가능

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


0개의 댓글