Today I Learned
- 고차 함수
고차 함수(higher order function)는 함수를 전달인자(argument)로 받을 수 있고, 함수를 리턴할 수 있는 함수이다.
고차 함수는 전달인자로 함수를 받을 수 있는데, 이때 전달인자로 전달되는 함수를 콜백 함수(callback function)라고 한다. 콜백 함수를 전달받은 고차 함수(caller)는 함수 내부에서 이 콜백 함수를 호출할 수 있고, 조건에 따라 콜백 함수의 실행 여부를 결정할 수도 있다. 함수를 전달인자로 받는 함수를 커링 함수(currying function)라고도 하는데, 고차 함수가 커링 함수를 포함하는 개념이다.
// doubleNum의 콜백 함수
function double(num) {
return num * 2;
}
function doubleNum(func, num) {
return func(num);
}
doubleNum(double, 3); // 6
function adder(added) {
return function (num) {
return num + added;
};
}
const add2 = adder(2);
add2(5); // 7
adder(2)(5) // 7
// doubleAdder의 콜백 함수
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
doubleAdder(3, double)(2) // 8
function makeBetweenFunc (min, max) {
return function (num) {
return num >= min && num <= max;
};
}
let isChild = makeBetweenFunc (0, 18);
let isAdult = makeBetweenFunc (19, 65);
let isSenior = makeBetweenFunc (66, 120);
isChild(10) // true;
isAudlt(18) // false;
isSenior(100) // true;
컴퓨터 과학에서 추상화(abstraction)는 복잡한 자료, 모듈, 시스템 등으로부터 핵심적인 개념 또는 기능을 간추려 내는 것을 말한다. (위키백과)
고차 함수는 단순히 값(value)을 전달받아 처리하는 수준의 함수에서 벗어나 함수(사고의 묶음)를 전달받아 처리함으로써 함수의 추상화를 한단계 더 높인다.
이러한 고차 함수를 통해 보다 높은 수준(higher order)에서 생각할 수 있으며, 추상화의 수준이 높아지면 생산성도 높일 수 있다.
repeat()
➡️ 단순히 값을 전달받아 처리하는 수준의 함수
function repeat(times, value) {
return [...Array(times).keys()].map(() => value)
}
repeat(3, "foo") // ['foo', 'foo', 'foo']
repeatedly()
➡️ 고차 함수 (함수(사고의 묶음)를 전달받아 처리하는 함수)
function repeatedly(times, func) {
return [...Array(times).keys()].map(func)
}
repeatedly(3, () => "foo") // ['foo', 'foo', 'foo']
repeatedly(3, i => `foo${i}`) // ['foo0', 'foo1', 'foo2']
위 예시의 repeat
함수와 repeatedly
함수를 비교해 보자. repeat
함수는 단순히 반복 횟수와 리턴값을 받아 그 값을 배열로 리턴하는 함수이다. 이에 비해 repeatedly
함수는 map() 함수의 행동을 결정짓는 함수 func을 인자로 넘겨 map() 함수 반복마다 다른 문자열로 구성된 배열을 반환받는 행동을 한다. 고정된 값을 그 값을 만들어내는 행동(함수)으로 한 단계 추상화하여 만들어 낸 것이다.
내장 고차 함수에 해당하는 배열 메서드들 중 filter
, map
, reducer
에 대해 알아보자.
filter()
메서드는 주어진 함수의 테스트를 통과하는 모든 요소를 모아 새로운 배열로 반환한다. 즉, 조건에 맞는 데이터만 분류(filtering)할 때 사용한다.
// 예시 (1)
const nums = [1, 2, 3, 4]
const evenNums = nums.filter((num) => num%2 === 0);
console.log(evenArray); // [2, 4]
// 예시 (2)
const isLteFive = function(str) {
return str.length <= 5;
}
const words = ['hello', 'word', 'javaScript', 'happy', 'hacking'];
const wordsLteFive = words.filter(isLteFive);
console.log(wordsLteFive); // ['hello', 'word', 'happy']
map()
메서드는 배열 내의 모든 요소 각각에 대하여 주어진 함수를 호출한 결과를 모아 새로운 배열을 반환한다. 즉, 하나의 데이터를 다른 데이터로 매핑(mapping) 할 때 사용한다.
// 예시 (1)
const nums = [1, 2, 3, 4];
const doubledNums = nums.map((num) => num * 2);
console.log(doubledNums); // [2, 4, 6, 8]
// 예제 (2)
const users = [
{ name: 'Jane', age: 20 },
{ name: 'Hary', age: 30 },
{ name: 'Amy', age: 40 }
];
// 예제 (2) - 1
const usersName = users.map((user) => user.name)
console.log(usersName) // ['Jane', 'Hary', 'Amy']
// 예시 (2) - 2
const usersInTheNextYear = users.map((user) => ({ ...user, age: user.age + 1 }))
console.log(usersInTheNextYear)
// [{ name: 'Jane', age: 21 }, { name: 'Hary', age: 31 }, { name: 'Amy', age: 41 }];
reduce()
메서드는 배열의 각 요소에 대해 주어진 리듀서 (reducer) 함수를 실행하고, 하나의 결과값을 반환한다. 즉, 여러 데이터를, 하나의 데이터로 응축(reduce)할 때 사용한다.
// 예시 (1)
const nums = [1, 2, 3, 4];
// 0 + 1 + 2 + 3 + 4
const initialValue = 0;
const sumWithInitial = nums.reduce(
(accumulator, currentValue) => accumulator + currentValue,
initialValue
);
console.log(sumWithInitial); // 10
// 예시 (2)
function joinName(resultStr, user) {
resultStr = resultStr + user.name + ', ';
return resultStr;
}
const users = [
{ name: 'Jane', age: 20 },
{ name: 'Hary', age: 30 },
{ name: 'Amy', age: 40 }
];
const usersName = users.reduce(joinName, '').slice(0, -2);
console.log(usersName); // 'Jane, Hary, Amy'
참고