대표적인 일급 객체 중 하나
특별한 대우를 받는 함수
const foo = function() {
console.log("foobar");
}
// Invoke it using the variable
foo();
변수에 할당할 수 있기 때문에, 함수를 배열의 요소나 객체의 속성값으로 저장가능 -> 함수를 데이터(string, number, boolean, array, object)를 다루듯이 다룰 수 있음
function sayHello() {
return "Hello, ";
}
function greeting(helloMessage, name) {
console.log(helloMessage() + name);
}
// Pass `sayHello` as an argument to `greeting` function
greeting(sayHello, "JavaScript!");
// ** Here, sayHello is a Callback function.
콜백 함수(callback function) :
다른 함수(caller)의 인자(argument)로 전달되는 함수
어떤 작업이 완료되었을 때 호출하는 경우가 많아서, 답신 전화를 뜻하는 콜백이라는 이름
function sayHello() {
return function() {
console.log("Hello!");
}
}
// 1. Using a variable
const sayHello = function() {
return function() {
console.log("Hello!");
}
}
// 2. Using double parentheses
const myFunc = sayHello();
myFunc();
function sayHello() {
return function() {
console.log("Hello!");
}
}
sayHello()();
-ex) 위 코드의 반대 경우
콜백 함수를 전달받은 고차 함수는, 함수 내부에서 이 콜백 함수를 호출(invoke) 할 수 있다. caller(다른 함수)는 조건에 따라 콜백 함수의 실행 여부 및 실행 횟수 등을 결정
커리 함수 :
'함수를 리턴하는 함수'를 고안해 낸 논리학자 하스켈 커리(Haskell Curry)의 이름을 땀
고차 함수가 커리 함수를 포함
자바스크립트는 고차 함수를 다수 지원하고 있다.
그 중 대표적인 array methods
forEach, find, filter, map, reduce, sort, some, every
기존배열 수정 x
배열의 각 요소가
특정 논리(함수)에 의해
다른 요소로 지정(map) 합니다.
문제
만화책 식객 27권의 정보가 배열에 담겨있습니다. 각 책의 부제(subtitle)만 담은 배열을 만드세요.
수도코드
배열의 각 요소 : 각 식객 1- 27권의 정보
특정 논리(함수) : 책 한 권의 부제를 찾습니다.
다른 요소로 지정 : 각 식객 1- 27권의 부제
실제 코드
map은 이렇게 하나의 데이터를 다른 데이터로 맵핑(mapping) 할 때 사용합니다.
const cartoons = [
{
id: 1,
bookType: 'cartoon',
title: '식객',
subtitle: '어머니의 쌀',
createdAt: '2003-09-09',
genre: '요리',
artist: '허영만',
averageScore: 9.66,
},
{
id: 2,
// .. 이하 생략
},
// ... 이하 생략
]; // 만화책의 모음
const findSubtitle = function (cartoon) {
return cartoon.subtitle;
}; // 만화책 한 권의 제목을 리턴하는 로직(함수)
const subtitles = cartoons.map(findSubtitle); // 각 책의 부제 모음
배열의 filter 메소드: 모든 배열의 요소 중에서 특정 조건을 만족하는 요소를 걸러내는 메소드
걸러내기 위한 조건을 명시한 함수를 인자로 받
배열의 요소를, 인자로 전달되는 콜백 함수에 다시 전달합니다. 콜백 함수는 전달받은 배열의 요소를 받아 함수를 실행하고, 콜백 함수 내부의 조건에 따라 참(true) 또는 거짓(false)을 리턴
콜백함수를 만족하는 요소가 없는 경우, 빈 배열을 리턴한다.
그러나 filter 메소드에 들어가는 콜백 함수는 Deep equality를 통해 조건을 명확하게 밝히는 걸 권장합니다. 따라서 이 콘텐츠에서도 콜백 함수가 내부 조건에 따라 참(true) 또는 거짓(false)을 리턴하도록 구현하길 권장합니다._
요소 중 원하는 값만 필터링
배열의 각 요소가
특정 논리(함수)에 따르면, 사실(boolean)일 때
따로 분류합니다(filter).
조건에 맞는 데이터만 분류(filtering)
문제
만화책 식객 27권의 정보가 배열에 담겨있습니다. 출판년도가 2003년인 단행본만 담은 배열을 만드세요.
수도코드
배열의 각 요소 : 각 식객 1- 27권의 정보
특정 논리(함수) : 책의 출판년도가 2003년입니다. (true / false)
따로 분류 : 출판년도가 2003년인 책의 정보
실제 코드
filter는 이렇게 조건에 맞는 데이터만 분류(filtering) 할 때 사용합니다.
const cartoons = [
{
id: 1,
bookType: 'cartoon',
title: '식객',
subtitle: '어머니의 쌀',
createdAt: '2003-09-09',
genre: '요리',
artist: '허영만',
averageScore: 9.66,
},
{
id: 2,
// .. 이하 생략
},
// ... 이하 생략
]; // 단행본의 모음
const isCreatedAt2003 = function (cartoon) {
const fullYear = new Date(cartoon.createdAt).getFullYear()
return fullYear === 2003;
}; // 단행본 한 권의 출판판년도가 2003인지 확인하는 함수
const filteredCartoons = cartoons.filter(isCreatedAt2003); // 출판년도가 2003년인 책의 모음
초기값 정하지 않음 : 배열의 첫번째 요소가 초기값됨
초기값 정함 : 배열의 현재 요소가 초기값
누적값 리턴/ 다양한 타입에 다양한 기능적용 가능
여러 데이터를, 하나의 데이터로 응축(reduce)
콜백함수의 리턴값은 다음 배열 요소의 누산기(acc)에 들어간다.
arr.reduce(callback(acc, cur, idx, arr), initialValue);
문제
만화책 식객 27권의 정보가 배열에 담겨있습니다. 각 단행본의 평점의 평균을 리턴하세요.
수도코드
배열의 각 요소 : 각 식객 1- 27권의 정보
응축하는 방법 (함수) : 각 단행본의 평점을 누적값에 더합니다.
원하는 형태 : 숫자로 누적합니다.
응축된 결과 : 각 단행본의 평점의 합을 단행본의 길이로 나눈 평점의 평균
실제 코드
reduce는 이렇게 여러 데이터를, 하나의 데이터로 응축(reduce)할 때 사용합니다.
const cartoons = [
{
id: 1,
bookType: 'cartoon',
title: '식객',
subtitle: '어머니의 쌀',
createdAt: '2003-09-09',
genre: '요리',
artist: '허영만',
averageScore: 9.66,
},
{
id: 2,
// .. 이하 생략
},
// ... 이하 생략
]; // 단행본의 모음
const scoreReducer = function (sum, cartoon) {
return sum + cartoon.averageScore;
}; // 단행본 한 권의 평점을 누적값에 더한다.
let initialValue = 0 // 숫자의 형태로 평점을 누적한다.
const cartoonsAvgScore = cartoons.reduce(scoreReducer, initialValue) / cartoons.length;
// 모든 책의 평점을 누적한 평균을 구한다.
reduce의 색다른 사용법
배열을 문자열로
배열을 객체로
for문을 대체하는 고차 함수
내부에서 주어진 배열을 순회하면서 연산을 수행
for문과는 다르게 break, continue를 사용할 수 없어서 배열의 모든 요소를 중단없이 순회
for문 보다는 성능이 좋지는 않지만 가독성이 더 좋고 함수형 프로그래밍에 부합하기 때문에 꼭 필요한 경우가 아니라면 for문을 대신하여 사용할 것이 권장됨
const numberArr = [1, 2, 3, 4, 5];
let total = 0;
numberArr.forEach((item) => {
total += item;
});
console.log(total); // 15
forEach() 메서드의 콜백 함수에는 다음과 같이 주어진 배열의 요소값, 인덱스, this(순회중인 배열) 3개의 파라미터를 순차적으로 전달할 수 있다.
const numberArr = [1, 2, 3, 4, 5];
let total = 0;
numberArr.forEach((item, index, thisArr) => {
console.log('thisArr', thisArr);
console.log('index', index);
console.log('item', item);
total += item;
});
console.log(total); // 15
배열의 원소 위치가 연속적이지 않은 (삭제 및 초기화하지 않은)희소 배열의 경우 존재하지 않는 요소는 순회 대상에서 제외됨. 이는 map(), reduce(), filter() 메서드에서도 동일하게 적용
const numberArr = [1, , 3];
numberArr.forEach((item) => {
console.log('item', item); // item 1, item 3
});
forEach(): 각 요소를 참조한 연산이 이루어짐 ,return value가 undefined,반복문을 대체하여 사용
map(): 각 요소를 다른 값으로 맵핑한 새로운 배열이 반환됨, 콜백 함수의 결과로 새로운 배열을 생성하고자할 때
const numberArr = [1, 2, 3, 4, 5];
const numberForEachArr = numberArr.forEach((item) => {
return item;
});
const numberMapArr = numberArr.map((item) => {
return item;
});
console.log(numberForEachArr); // undefined
console.log(numberMapArr); // [1, 2, 3, 4, 5]
주어진 배열을 순회하면서 콜백 함수 실행의 반환값이 true에 해당하는 첫번째 요소를 반환
true를 리턴하는 요소가 없는 경우 undefined를 리턴
find() 메서드의 콜백 함수에는 주어진 배열의 요소값, 인덱스, this(주어진 배열) 3개의 파라미터를 순차적으로 전달. 또한 find() 메서드와는 달리 filter() 메서드는 반환값이 true로만 구성된 새로운 배열을 생성하여 반환
const numberArr = [1, 3, 3, 5, 7];
const objectArr = [
{ name: 'Harry', age: 20 },
{ name: 'Kim', age: 30 },
{ name: 'Steve', age: 40 }
];
console.log(objectArr.find(item => item.age === 20)); // {name: "Harry", age: 20}
console.log(numberArr.find(item => item === 3)); // 3
console.log(numberArr.filter(item => item === 3)); // [3, 3]
요소의 값이 아니라 인덱스를 찾고 싶은 경우, findIndex() 사용가능
const arr = [1, 2, 3, 4, 5];
const idx = arr.findIndex(el => el===3);
console.log(idx); // 2
배열의 요소를 적절한 위치에 정렬하고, 그 배열을 반환
원본 배열을 수정하는 mutable 메서드
compareFunction(콜백 함수)가 제공되지 않으면 요소를 문자열로 변환 후 유니 코드 코드 포인트 순서로 문자열을 비교하여 정렬
arr.sort(callback(a, b));
compareFunction에는 배열의 서로 다른 요소가 두 개 온다. (a, b)
/* 내림차순 정렬 예제 */
let arr = [5, 1, 3, 2, 4];
arr.sort(function (a, b) {
return a-b;
});
console.log(arr); // [1, 2, 3, 4, 5]
배열 안의 모든 요소를 순회하면서, 콜백 함수가 하나라도 true를 반환하면 true를 반환하고, 모두 false를 반환하면 false를 반환한다.
function isBiggerThan6(el) => {
if (el > 6){
return true;
}
else {
return false;
};
}
const arr1 = [1, -3, 4, 2, 8, 1];
const arr2 = [-17, 0, 3, -2];
console.log(arr1.some(isBiggerThan6)); // true
console.log(arr2.some(isBiggerThan6)); // false
⛔빈 배열에서 호출하면 무조건 false를 반환
배열 안의 모든 요소를 순회하면서, 콜백 함수가 모두 true를 반환하면 true를 반환하고, 하나라도 false를 반환하면 false를 반환한다.
function isBiggerThan6(el) => {
if (el > 6){
return true;
}
else {
return false;
};
}
const arr1 = [8, 12, 51, 32];
const arr2 = [17, 20, 4, 10];
console.log(arr1.every(isBiggerThan6)); // true
console.log(arr2.every(isBiggerThan6)); // false
⛔빈 배열에서 호출하면 무조건 true를 반환
추상화(abstraction) : 복잡한 어떤 것을 압축해서 핵심만 추출한 상태로 만드는 것
추상화 = 생산성(productivity)의 향상
함수 = 값을 전달받아 값을 리턴한다 = 값에 대한 복잡한 로직은 감추어져 있다 = 값 수준에서의 추상화
고차 함수는 이 추상화의 수준을 사고의 추상화 수준으로 끌어올립니다.
값 수준의 추상화: 단순히 값(value)을 전달받아 처리하는 수준
사고의 추상화: 함수(사고의 묶음)를 전달받아 처리하는 수준
다시 말해 고차 함수를 통해, 보다 높은 수준(higher order)에서 생각할 수 있습니다.
고차함수 = 함수를 전달받거나 함수를 리턴한다 = 사고(함수)에 대한 복잡한 로직은 감추어져 있다 = 사고 수준에서의 추상화
각각의 작업(filter, map, reduce)은 별도의 함수로 분리되어, 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) {
// compose는 여러 개의 함수를 인자로 전달받아 함수를 리턴하는 고차 함수입니다.
// compose가 리턴하는 함수(익명 함수)는 임의의 타입의 data를 입력받아,
return function (data) {
// funcArgs의 요소인 함수들을 차례대로 적용(apply)시킨 결과를 리턴합니다.
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
추상화(abstraction)에 대해 설명할 수 있다.
추상화의 관점에서 고차 함수가 갖는 이점에 대해 설명할 수 있다.
고차 함수를 활용하여 프로그램을 작성할 수 있다