21일차

JiHun·2023년 5월 10일

부트캠프

목록 보기
20/56

고차함수

일급 객체

일급객체는 JavaScript에서 특별한 대우를 받는다. 일급 객체 중 하나가 함수다.

JavaScript에서 함수 취급

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

고차 함수(higher order function)

고차함수는 함수를 전달인자로 받을 수 있고, 함수를 리턴할 수 있는 함수다. 또한 함수를 인자로 받고, 함수를 리턴할 수도 있다.
이때 다른 함수의 전달인자로 전달되는 함수를 콜백 함수(callback function)라고 한다.

함수 내부에서 이 콜백 함수를 호출할 수도 있고, 조건에 따라 콜백 함수의 실행 여부를 결정할 수도, 아예 호출하지 않을 수도, 여러번 실행할 수도 있다.

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

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

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

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

2. 함수를 리턴하는 경우

function adder(added) {       // 함수 adder는 익명 함수를 리턴하는 고차 함수.
	return function (num) {
    	return num + added;
    }
}

let output = adder(5)(3);   // => 8; adder(5)는 함수를 리턴하기 때문에 "()"를 쓸 수 있다.

const add3 = adder(3);     // 함수를 리턴하는 adder(3) 함수는 add3이라는 변수에 저장했다. 
                           // JavaScript에서 함수는 일급 객체이기 때문에 변수에 저장할 수 있다.
output = add3(2);

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

function double(num) {
	return num * 2
}

function doubleAdder(added, func) {   // doubleAdder 는 함수를 전달인자로 받는 고차함수. 
                                      //인자 func는 함수 doubleAdder의 콜백 함수.
	const doubled = func(added);
  	return function(num){
		return num + doubled;
    }
}
doubleAdder(5, double)(3); // => 13; doubleAdder(5, double)는 함수이므로 "()"로 함수 호출을 할 수 있다.

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

내장 고차 함수

JavaScript에 기본적으로 내장된 고차 함수들이 있다. 그 중 메서드들 중 일부가 대표적인 고차 함수다.

filter

모든 배열의 요소 중에서 특정 조건을 만족하는 요소를 걸러내는 메서드다.

let arr = [1, 2, 3, 4];
let output = arr.filter(function(el) {
	if(el % 2 === 0){
    	return el;
	}
});
console.log(output) // => [2, 4]; 

배열의 요소들을 조건식 함수에 넣어서 true면, 요소를 배열에 넣고, false면 요소를 배열에서 뺀다. 이때 만들어진 배열은 기존 배열을 건드리지 않는 새로운 배열이다.

map

하나의 데이터를 다른 데이터로 매핑(mapping) 할 때 사용한다.

const arr = [{key:10}, {key:20}, {key:30}]

const findValues = function(value) {
	return value["key"];
}

const values = arr.map(findValues);
console.log(values) //=> [10, 20, 30]

reduce

const arr = [{key:10}, {key:20}, {key:30}]

return arr.reduce(function(acc, cur) {   // acc는 누적값, cur는 현재값.
	return acc + cur                     // 더해서 누적하는 거 말고도 누적값과 현재값을 비교하는 다양한 함수를 만들 수 있다. 
}, 0);

reduce 함수의 색다른 사용법

초기값 설정으로 누적하여 배열을 문자열로, 배열을 객체로 만들 수도 있다.

const maxValueKey = arr.reduce(function(acc, cur) {
	if(acc["key"] < cur["key"]) {
		return cur;
	} else if(acc["key"] >= cur["key"]) {
		return acc;
	}
});
console.log(maxValueKey);  // => {key: 30}

고차 함수의 중요성

.map(), .filter() 등등 많은 고차 함수들이 있다. 우리는 이 메서드들이 어떻게 생겨먹었는지 정확하게는 모르지만 어떤 값을 넣으면 어떤 값이 리턴되는지 알고 있다. 메서드의 복잡한 로직은 감춰져 있다.

메서드는 고차 함수를 추상적으로 표현했다고 볼 수 있다. 고차 함수를 통해 추상화의 수준을 높일 수 있고 그만큼 생산성도 높일 수 있다.

고차 함수와 추상화

어떤 데이터를 넣었을 때, 함수 하나에 넣어서 사용할 수 있다.

function 평균나이값(data) {
	const onlyMales = data.filter()         // 남자들만 모아놓은 배열
  	const onlyMaleAges = onlyMales.map()    // 남자들 나이만 모아놓은 배열
    const sumOfAges = onlyMaleAges.reduce() // 나이만 모아놓은 배열을 누적시켜 더하기
    return sumOfAges/ onlyMales.length
}

이렇게 만들면 순차적으로 만들 수 있다. 하지만 평균 나이만 구할 수 있는 작업만 수행하는 함수일 뿐이다.

하지만 추상화는 고차 함수를 통해 함수를 순서대로 결합하는 고차함수가 있다. 각각의 작업은 별도의 함수로 분리되어 사용 가능하며 또한, 고차 함수의 콜백 함수로써도 사용 가능하다.

function 남자만리턴(data) {
	return data.filter()
}
function 나이만리턴(data) {
	return data.map()
}
function 나이평균리턴(data) {
	const sum = data.reduce()
    return sum / data.length
}

function compose(...funcArgs) {
	return function (data) {
		let result = data;
      	for(i = 0; i < funcArgs.length; i++) {
        	result = funcArgs[i](result);
		}
      	return result;
	}
}

const getAverageAgeOfMale = compose(
	남자만리턴,
  	나이만리턴,
	나이평균리턴
)

const result = getAverageAgeOfMale(data);
console.log(result);

마지막으로

이제 진짜 어려워졌다. 자세히 봐야 한다. 보는 것도 힘든데 만드는 것은 더 어렵겠지? 천천히 함수를 따라가며 해보자.

profile
안녕하세요. 프론트엔드 개발자 송지훈입니다.

0개의 댓글