22sook00 logo
SookDev
🌳

고차함수를 사용하는 이유

tag
javascript
date
Sep 24, 2023
목차

고차함수는 무엇인가 Higher Order Function (HOF)

함수의 형태로 리턴할 수 있는 함수
함수는 자바스크립트에서 특별한 대우를 받는 일급객체라고 할 수 있다.
function double(num) { return num * 2; } function doubleAdder(added, func) { const doubled = func(added); return function (num) { return num + doubled; }; } const addTwice3 = doubleAdder(3, double); addTwice3(2); // --> 8
함수는 함수 표현식과 함수 선언식으로 나뉘는데, 호이스팅이 가능한 함수 선언식과 달리 함수표현식은 함수의 할당과 실행 위치에 따라 결과가 달라진다. 호이스팅 여부를 제외한다면 별다른 차이는 없으나, 함수 표현식은 변수에 저장될 수 있다는 것을 분명하게 보여준다.
콜백함수 : 다른 함수(caller) 의 인자(arg) 로 전달되는 함수
어떤 작업이 완료 되었을 때 호출하기 때문에 콜백함수라는 이름이 붙여졌다.
콜백함수를 전달받은 고차 함수는 함수 내부에서 콜백함수를 호출할 수 있다.
function double(num) { return num * 2; } function doubleNum(func, num) { return func(num); } let output = doubleNum(double, 4);
커리함수 : 함수를 리턴하는 함수
function adder(added) { return function (num) { return num + added; }; } let output = adder(5)(3); // -> 8 console.log(output); // -> 8 // adder가 리턴하는 함수를 변수에 저장할 수 있습니다. // javascript에서 함수는 일급 객체이기 때문입니다. const add3 = adder(3); output = add3(2); console.log(output); // -> 5
  • 변수에 할당할 수 있다.
    • 배열의 요소나 객체의 속성값으로 저장 가능
    • 함수도 데이터(string,number,array..)를 다루듯 다룰 수 있다.
  • 다른 함수의 인자로 전달될 수 있다. (콜백)
  • 다른 함수의 결과로 리턴될 수 있다. (커리)
  • 함수형 프로그래밍은 사이드이펙트를 피하고 불변성을 지켜 에러를 최소화 한다.
    • 하나의 함수가 다른 함수에 의존하지 않기 때문에 코드가 변경되도 사이드이펙트가 적다.
    • 외부요소에 의존하지 않고 매번 같은 동작을 한다.
  • 변수를 최소화 하여 프로그램 동작을 예측하기 쉽게 만든다.
  • map,reduce,filter 와 같은 내장 메서드는 인자로 함수를 받을 수 있다.
  • Function.prototype.bind() 메서드는 this 가 바인드 된 새 함수를 반환한다.
 
객체지향과의 비교
  • 객체지향은 데이터와 그 데이터와 연관된 연산에 대한 추상화가 용이하다.
  • 함수형 프로그래밍은 연산에 대한 추상화가 용이하다.
 

내장 고차함수 동작방식 이해하기

map, reduce, filter 는 우리가 잘 알고 있는 내장 고차함수다.
여기서 어떻게 고차함수 방식하는 동작인지 filter 를 예시로 보겠다.
Array.prototype.filter = function(func) { const arr = this; const newArr = [] for(let i = 0; i < arr.length; i++) { if (func(arr[i]) % 2 === 0) { newArr.push(this[i]) } } return newArr; }
const arr = [1,2,3,4] const arrFilter = arr.filter((num)=> num % 2 === 0)
위의 간단한 예시에서 filter 는 arr 의 요소를 인자로 전달되는 콜백함수에 num 으로 다시 전달된다.
이 콜백함수에서 true 조건에 걸리는 값을 리턴하게 된다.
 

고차함수의 사용이유

추상화 : 복잡한 어떤것을 압축하여 핵심만 추출한 상태로 만드는 것
예를들면 -1 을 직접적으로 표현하는것은 어렵지만, 0보다 1만큼 작은 수 라고 설명할 수 있다.
한가지 더 예를 들자면, 개발자도구 창의 콘솔탭에서 어떠한값을 입,출력 할 때 어떤 과정으로 출력되는지 알기 어렵지만 출력하는 방법은 알고 있다.
이렇듯 일상 생활에서도 인간은 추상화를 통해 좀 더 쉽게 생각하고 표현이 가능해진다.
함수도 이와 비슷한 원리로, 어떠한 값이 들어올것이라 예상하고 자주 반복되는 로직을 별도의 함수로 작성한다.
고차함수는 함수의 추상화를 한 단계 더 높여 생산성을 상승시킨다.
함수의 추상화는 단순히 어떠한 값을 인자로 받는것을 추상화 한다면, 고차함수는 함수를 전달받아 처리하는 높은 수준의 추상화다.
const data = [ { gender: 'male', age: 24, }, { gender: 'male', age: 25, }, { gender: 'female', age: 27, }, { gender: 'female', age: 22, }, ]; //남성들의 평균 나이를 구하는 하나의 함수 function getAverageAgeOfMaleAtOnce(data) { const onlyMales = data.filter(function (d) { return d.gender === 'male'; }); const numOfMales = onlyMales.length; const onlyMaleAges = onlyMales.map(function (d) { return d.age; }); const sumOfAges = onlyMaleAges.reduce(function (acc, cur) { return acc + cur; }, 0); return sumOfAges / numOfMales; }
값만 받아 처리하는 수준의 추상화
//입력된 함수를 순차적으로 실행하는 고차함수 compose function getOnlyMales(data) { return data.filter(function (d) { return d.gender === 'male'; }); } function getOnlyAges(data) { return data.map(function (d) { return d.age; }); } function getAverage(data) { const sum = data.reduce(function (acc, cur) { return acc + cur; }, 0); return sum / data.length; } // 여러 개의 함수를 인자로 전달받아 함수를 리턴하는 고차 함수 function compose(...funcArgs) { return function (data) { let result = data; for (let i = 0; i < funcArgs.length; i++) { result = funcArgs[i](result); } return result; }; } // compose를 통해 함수들이 순서대로 적용된다는 것이 직관적으로 드러난다. // 각각의 함수는 다른 목적을 위해 재사용(reuse) 가능. const getAverageAgeOfMale = compose( getOnlyMales, // 배열을 입력받아 배열을 리턴하는 함수 getOnlyAges, // 배열을 입력받아 배열을 리턴하는 함수 getAverage // 배열을 입력받아 `number` 타입을 리턴하는 함수 ); const result = getAverageAgeOfMale(data); console.log(result); // --> 26
 

참조
🔗 
🔗