JavaScript의 대표적인 일급 객체 중 하나인 함수는 특별한 취급을 받는다.
const square = function(num) {
return num * num;
}
let output = square(4); // 16
// 변수 square에는 함수가 할당되어 있으므로(일급 객체), 함수 호출 연산자 '()'를 사용할 수 있다.
고차 함수를 쓸 수 있는 이유
: 함수가 일급 객체여서!
: 함수를 전달인자(argument)로 받을 수 있고, 함수를 리턴할 수 있는 함수
function double(num) {
return num * 2;
}
function doubleNum(func, num) { // 콜백 함수 func을 전달인자로 받는 고차 함수 doubleNum
return func(num);
}
let output doubleNum(double, 4); // 8
콜백 함수(callback function)
: 다른 함수(caller)에 전달인자로 전달되는 함수
어떤 작업이 완료되었을 때 호출하는 경우가 많아, "답신 전화"라는 뜻의 콜백 함수라는 이름이 붙여졌다.
function adder(added) {
return function(num) { // 익명 함수를 리턴하는 고차 함수이자 커링 함수 adder
return num + added;
}
}
let output = adder(5)(3); // 8
const add3 = adder(3); // adder가 리턴하는 함수를 변수에 저장할 수 있다.(함수는 일급 객체이므로)
output = add3(2); // 5
커링 함수(curring function)
: 함수를 리턴하는 함수
커링 함수라는 용어를 사용하는 경우에는, 고차 함수라는 용어를 "함수를 전달인자로 받는 함수"에만 한정해 사용하기도 한다.
그러나 정확하게 구분하자면, 고차 함수가 커링 함수를 포함한다.
function double(num) {
return num * 2;
}
function doubleAdder(added, func) { // 콜백 함수 func을 전달인자로 받고,
const doubled = func(added);
return func(num) { // 전달받은 함수를 리턴하는 고차 함수 doubleAdder
return doubled + num;
}
}
doubleAdder(5, double)(3); // 10 + 3 = 13
const addTwice3 = doubleAdder(3, double); // doubleAdder가 리턴하는 함수를 변수에 저장할 수 있다. (함수는 일급 객체이므로)
addTwice3(2); // 6 + 2 = 8
JavaScript에는 기본적으로 내장된 고차 함수가 있다.
그 중에서 배열 메소드 중 일부가 대표적인 고차 함수에 해당한다.
ex. filter, map, reduce, forEach, find, sort, some, every ...
arr.filter(fn)
: 배열의 각 요소를 콜백 함수에 전달해 true
를 반환하는 요소들만 새로운 배열로 만들어 반환하는 메소드
const isEven = function(num) {
return num % 2 === 0; // true나 false를 반환한다.
}
const arr = [1, 2, 3, 4, 5];
const output = arr.filter(isEven); // [2, 4]
filter 메소드가 고차 함수인 이유
filter 메소드의 전달인자로 함수를 전달하기 때문 (콜백 함수)
Array.prototype.filter = function(func) {
const arr = this;
const newArr = []
for(let i = 0; i < arr.length; i++) {
if (func(arr[i]) === true) {
newArr.push(this[i])
}
}
return newArr;
}
arr.map(fn)
: 배열의 각 요소에 콜백 함수에 적용시켜 새로운 배열로 만들어 반환하는 메소드
const multiply2 = function(num) {
return num * 2;
}
const arr = [1, 2, 3, 4, 5];
const output = arr.map(multiply2); // [2, 4, 6, 8, 10]
const multiply3 = function(num, idx) {
return `${idx}: ${num * 3}`;
}
const arr = [1, 2, 3, 4, 5];
const output = arr.map(multiply3);
// ['0: 3', '1: 6', '2: 9', '3: 12', '4: 15']
arr.reduce(fn)
: 배열의 각 요소를 콜백 함수에 맞게 하나로 응축시킨 값을 리턴하는 메소드
const arr = [1, 2, 3, 4, 5];
arr.reduce((acc, cur) => {
return acc + cur;
}, initialValue) // 15
arr.every(fn)
: 배열 안의 모든 요소가 콜백 함수를 통과하면 true
, 하나라도 통과하지 못하면 false
를 반환하는 메소드
const arr = [1, 2, 3, 4, 5];
arr.every((el) => el < 10); // true
arr.every((el) => el < 5); // false
arr.sort(compareFn)
: 배열의 요소를 정렬한 후 원 배열을 반환하는 메소드
const arr = [5, 3, 4, 2, 1, 10];
arr.sort(); // [1, 10, 2, 3, 4, 5]
// 문자열 "10"은 유니 코드 순서에서 "2" 앞에 온다.
const arr = ['d', 'a', 'c', 'e', 'b'];
arr.sort(); // ['a', 'b', 'c', 'd', 'e']
a - b
를 리턴하도록 하면 된다.Infinity
및 NaN
이 포함되어 있지 않은 경우)const arr = [5, 3, 4, 2, 1, 10];
arr.sort((a, b) => a - b); // [1, 2, 3, 4, 5, 10]
❔ 학습 후 궁금한 점
- 커링 함수? 클로저 함수?
- 새로운 배열을 반환한다. = immutable?
- 메서드와 함수의 차이는 무엇인지?