TIL 16 | 고차함수, 배열고차함수

dk.han·2021년 8월 10일
0
post-thumbnail

고차함수란? (Higher order function)

  • 함수를 인자로 전달받거나 함수를 결과로 반환하는 함수를 말한다.
  • 자바스크립트의 함수는 일급 객체이므로 값처럼 인자로 전달할 수 있으며 반환할 수도 있다.

일급객체가 뭔데?

일급 객체(first-class object)란 생성, 대입, 연산, 인자 또는 반환값으로서의 전달 등 프로그래밍 언어의 기본적 조작을 제한없이 사용할 수 있는 대상을 의미한다.

일급객체의 조건

  • 무명의 리터럴로 표현이 가능하다.
  • 변수나 자료 구조(객체, 배열 등)에 저장할 수 있다.
  • 함수의 매개변수에 전달할 수 있다.
  • 반환값으로 사용할 수 있다.

Javascript의 함수는 위의 조건을 모두 만족하므로 Javascript의 함수는 일급객체이다.
따라서 Javascript의 함수는 흡사 변수와 같이 사용할 수 있으며 코드의 어디에서든지 정의할 수 있다.

즉, 함수를 리턴하는 함수', '함수를 인자로 받는 함수' 를 고차함수라고 할 수 있다.

그럼 고차함수를 왜 쓰는거야?

오늘 고차함수라는 컨텐츠에 대해서 배우면서 가장 궁금했던 부분이다.
왜 쓸까...? 라고 생각했을 때 가장 먼저 든 생각은 '고차원적인 무엇인가를 구현해 내기 위해서는 연히 보다 복잡하면서 어려운 방법들이 사용되야 하니까...?'
이 생각이 전혀 틀린 말은 아니었으나 정확한 이유도 아니었다.
여러 이유가 있겠으나 그 중 가장 핵심적인 이유는 추.상.화!

추상화(abstraction)

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

추상화의 예로 스마트폰으로 카카오톡이나 페이스북 메신저를 통해 친구에게 'ㅇㅇ'이란 메세지를 보내면, 그 순간 스마트폰은 기지국과 약 20개의 메세지를 주고받는다. 하지만 우리는 이런 것들을 전부 알지 못하고, 알 필요도 없다. 그러나 입력창에 메세지를 입력하고 전송 버튼을 누르면, 내 친구가 메세지를 받는다는 사실은 알고 있다.
즉, 이 메세지를 주고받게 만드는 복잡한 과정들은 모르지만 결과적으로 메세지를 주고 받을수 있다는 사실이 핵심이며 추상화의 결과이다.

일반적인 함수를 통해 얻은 추상화를 '값 수준에서의 추상화'라 한다.

  • 함수 = 값을 전달받아 값을 리턴한다 = 값에 대한 복잡한 로직은 감추어져 있다 = 값 수준에서의 추상화
  • 값 수준의 추상화: 단순히 값(value)을 전달받아 처리하는 수준

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

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

즉, 추상화의 수준이 높아지는 만큼, 생산성도 비약적으로 상승하기 때문에 고차함수를 사용한다.

배열 고차 함수

1. arr.forEach(callback( ele, index, array ) )

  • index, array는 optional이다.
  • 배열 요소 각각에 대해서 인자로 주어진 함수를 실행한다.
  • forEach 메소드는 원본 배열(this)을 변경하지 않는다. but 콜백 함수로 변경할 수 있다.
  • for 문과는 달리 break 문을 사용할 수 없다.
const numbers = [1, 2, 3];
let pows = [];

numbers.forEach(function (item) {
  pows.push(item ** 2);
});

console.log(pows); // [ 1, 4, 9 ]

2. arr.filter ( callback ( ele, index, array ) )

  • index, array는 optional이다.
  • 각 요소에 대하여 인자로 주어진 콜백함수의 실행 결과가 true인 배열 요소의 값만을 추출한 새로운 배열을 반환한다.
  • 배열에서 특정 케이스만 필터링 조건으로 추출하여 새로운 배열을 만들고 싶을 때 사용한다. 이때 원본 배열은 변경되지 않는다.
const numbers = [1, 2, 3, 4, 5]; 
const result = numbers.filter(number => number > 3); 

console.log(numbers); // [1, 2, 3, 4, 5]; 

console.log(result); // [4, 5]

3. arr.map ( callback ( ele, index, array ) )

  • index, array는 optional이다.
  • 배열을 순회하며 요소 값을 다른 값으로 mapping하기 위한 함수이다.
const numbers = [1, 2, 3, 4];
const result = numbers.map((ele) =>  ele*2 )

console.log(numbers) // [1, 2, 3, 4]

console.log(result) // [2, 4, 6, 8]

4. arr.reduce ( callback ( accumulator, currentValue, currentIndex, array), initialValue)

  • accumulator, currentValue 를 제외한 나머지는 optional 이다.
  • 배열의 각 요소에 대해 주어진 콜백함수를 실행하고, 하나의 결과값을 반환한다.
  • initialValue를 설정한 경우
    accumulator는 initialValue와 같고 currentValue는 배열의 첫 번째 값과 같다.
  • initialValue를 설정하지 않은 경우
    accumulator는 배열의 첫 번째 값과 같고 currentValue는 두 번째와 같습니다.
const numbers = [1, 2, 3, 4];

let result1 = numbers.reduce((acc, cur) => acc+cur) // 초기값 설정 x
let result2 = numbers.reduce((acc, cur) => {return acc+cur}, 10 ) // 초기값 10

console.log(result1) // 10
console.log(result2) // 20

이렇게 숫자 계산에만 쓰이는 것이 아니다.
배열을 객체로 or 객체를 배열로 등등 여러곳에 응용하여 쓸 수 있다.
한가지 예시로 수업시간에 배운것을 보면

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, {});
/*
{
  T: [
    { name: 'Tim', age: 40 }
  ],
  S: [
    { name: 'Satya', age: 30 },
    { name: 'Sundar', age: 50 }
  ]
}
*/

콜백함수의 로직을 통해 주소록을 만들기도 한다.
처음엔 이게 진짜 뭔소린가 했다.... 오늘 이걸 이해 할 수 있던거 만으로도 정말 만족 ㅠㅠ

4가지 이외에도 더 있으나 4가지만 직접 다뤄보았기 때문에 이것만 포스팅 하도록 하자.
그리고 4개가 가장 powerful 하고 사용 빈도도 높다고 한다.

나머지는 나중에 쓸 일이 있으면 그때 포스팅 하도록 하겠다.

마무리

고차함수에 대해 몇번 보았으나 잘 이해가 가지않아서 힘들었었다.
근데 오늘 pair 수업에서 파트너가 개념에 대해 너무 잘 알고 있었고, 설명을 잘 해주셔서
이해하는데 큰 도움이 됫다. 정말 은인...

아직 배열의 고차함수 밖에 알지 못하지만 이것의 파워풀함은 느낄 수 있었다.

고차함수들을 섞어서 사용한다면 정말 효율적인 코드를 짤 수도 있겠다는 생각을 했다.

아직 완벽히 다룰줄 아는 건 아니니, 반복적인 복습으로 까먹지 않도록 해야겠다.

0개의 댓글