(TIL) D+19 고차함수

JulyK9·2022년 7월 25일
0

고차함수

일급객체

  • 특별한 대우를 받는 일급객체(first-class citizen)
  • JS에서 대표적인 일급객체중 하나는 '함수'!

JS에서 함수가 일급객체인 특징

  1. 변수에 할당 가능
    => 함수를 배열의 요소나 객체의 속성값으로 저장 가능, 함수를 데이터처럼 다룰 수 있음
  2. 다른 함수의 전달인자(argument)로 전달될 수 있음
    => 즉, 함수를 담은 변수를 전달인자로 받을 수 있음
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);
console.log(output); // -> 8
// 함수를 인자로 받고, 함수를 리턴하는 경우

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. 다른 함수의 결과로서 리턴될 수 있음
    => 함수 내부에서 변수에 함수를 할당할 수 있고 함수는 이 변수를 리턴할 수 있음
    => 변수에 할당하지 않고 함수를 바로 이용할 수 있음
    => 콜백함수 : 다른 함수(caller)의 전달인자(argument)로 전달되는 함수
    => 콜백 함수를 전달받은 고차 함수(caller)는, 함수 내부에서 이 콜백 함수를 호출(invoke)할 수 있고, 조건에 따라 콜백 함수의 실행 여부를 결정할 수도 있음
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

cf) 커링함수 : 함수를 리턴하는 함수

  • 커링 함수라는 용어를 사용하는 경우에는, 고차 함수라는 용어를 '함수를 전달인자로 받는 함수'에만 한정해 사용하기도 하지만 정확하게 구분하자면 고차함수가 커링함수를 포함함.
  • 클로저 함수와 거의 같은 개념이라고 보면됨, 내부함수에서 외부함수를 참조하기 때문

내장 고차 함수

arr.filter()

  • 배열의 요소 중에서 특정 조건을 만족하는 요소를 걸러내는 메서드
  • 조건에 맞는 데이터만 분류(filtering) 할 때 사용
  • 배열의 각 요소에 콜백 함수를 적용시켰을 때 true를 리턴하는 요소들만 모은 새로운 배열을 리턴
  • 기존 배열을 수정하지 않음
  • 필터링 조건은 filter 메서드의 전달인자로 전달됨. 전달되는 조건이 함수 형태로
  • 걸러내기 위한 조건을 명시한 함수를 전달인자로 받기 때문에 filter 메서드가 고차함수가 됨
  • filter 메서드는 배열의 요소를 콜백 함수에 전달. 콜백 함수는 전달받은 배열의 요소를 받아 함수를 실행하고, 콜백 함수 내부의 조건에 따라 참(true) 또는 거짓(false)을 리턴

arr.map()

  • 배열의 각 요소가 / 특정 논리(함수)에 의해 / 다른 요소로 지정(map) 됨
  • 하나의 데이터를 다른 데이터로 매핑(mapping)할 때 사용
  • 배열의 각 요소에게 동일한 행동을 준 값에 대해 모두 반환함
  • 배열의 각 요소에 콜백함수를 적용시켜 새로운 배열을 리턴 (정말 많이 씀)
  • 콜백함수에 두번째 전달인자를 줄 경우 인덱스를 가져옴) mdn 참조

arr.reduce()

  • 배열을 하나의 값으로 만들어 줌
  • 배열의 각 요소를 / 특정 방법(함수)에 따라 / 원하는 형태로 / 응축함(reduction)
  • 배열의 각 요소를 콜백 함수에 맞게 하나로 응축 시킨 값을 리턴 (초기값, 누적값(acc), 현재값(cur))
  • 먼저, 초기값이 있냐없냐 확인!! (핵심)
  • 초기값이 없으면 배열의 첫번째 요소가 누적값이 되고, 현재값은 배열의 두번째 요소가 됨
  • 초기값이 있으면 배열의 첫번째 요소가 현재값이 되면서 진행
  • 문자열이나 숫자 등을 합치거나 뺄 수 있음
  • 제일 작은 것, 큰 것을 비교할 수 있음
  • 배열 이외에 다른 형태(객체)로도 만들 수 있는 등 활용도가 높음
  • 배열을 문자로
// 배열의 각 요소 : 유저 정보
// 응축하는 방법 (함수) : 하나의 유저의 이름과 쉼표를 이어 붙임(concat)
// 원하는 형태 : 문자열로 누적합니다.
// 응축된 결과 : 쉼표로 구분되는 모든 유저의 이름

function joinName(resultStr, user) {
  resultStr = resultStr + user.name + ', ';
  return resultStr;
}

let users = [
  { name: 'Tim', age: 40 },
  { name: 'Satya', age: 30 },
  { name: 'Sundar', age: 50 }
];

users.reduce(joinName, '');
  • 배열을 객체로
// 배열의 각 요소 : 유저 정보
// 응축하는 방법 (함수) : 유저 한 명의 이름 중 첫 글자를 주소록 객체 속성의 키(key)로, 유저의 정보를 주소록 객체 속성의 값(value)으로 추가
// 원하는 형태 : 주소록 객체에 누적합니다.
// 응축된 결과 : 모든 유저의 정보가 알파벳으로 구분된 주소록

function makeAddressBook(addressBook, user) {
  let firstLetter = user.name[0];

  if(firstLetter in addressBook) {
    addressBook[firstLetter].push(user);
  } else {
    addressBook[firstLetter] = [];
    addressBook[firstLetter].push(user);
  }

  return addressBook;
}

let users = [
  { name: 'Tim', age: 40 },
  { name: 'Satya', age: 30 },
  { name: 'Sundar', age: 50 }
];

users.reduce(makeAddressBook, {});**

고차함수는 왜 쓰는가?

  • 추상화의 관점에서 고차 함수를 통해 사고 수준의 추상화를 달성할 수 있음

추상화

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

  • 추상화 = 생산성(productivity)의 향상
  • 프로그램을 작성할 때, 자주 반복해서 사용하는 로직은 별도의 함수로 작성하는 것도 추상화의 좋은 사례
  • 추상화의 관점에서 함수를 바라보면, 함수는 사고(thought) 또는 논리(logic)의 묶음
  • 함수를 통해 얻은 추상화를, 한 단계 더 높인 것이 고차 함수
  • 값 수준의 추상화: 단순히 값(value)을 전달받아 처리하는 수준
  • 사고의 추상화: 함수(사고의 묶음)를 전달받아 처리하는 수준
  • 함수 = 값을 전달받아 값을 리턴한다 = 값에 대한 복잡한 로직은 감추어져 있다 = 값 수준에서의 추상화
  • 고차 함수 = 함수를 전달받거나 함수를 리턴한다 = 사고(함수)에 대한 복잡한 로직은 감추어져 있다 = 사고 수준에서의 추상화

용어이해

  • 일급객체, 고차함수, 콜백함수, 커링함수
  • 혼동주의 : 콜백함수, 고차함수
profile
느리지만 꾸준하게. 부족하거나 잘못된 부분은 알려주시면 감사하겠습니다.

0개의 댓글