고차함수(Higher order function), 콜백함수, 내장 고차 함수

해리포터·2022년 5월 24일
0

JavaScript에서 함수는 일급객체(first-order citizen)이다.

일급 객체의 특징:

  • 변수에 할당이 가능하다.
  • 다른 함수의 전달인자로 전달이 가능하다.
  • 다른 함수의 리턴으로 사용할 수 있다.

고차 함수의 특징:

  • 함수를 전달인자로 전달 받는 함수 → 콜백 함수
  • 함수를 리턴하는 함수 → 커링 함수
    (참고: 함수가 일급 객체이기 때문에 고차함수로 활용이 가능하다.)

고차함수 vs. 콜백함수

함수의 매개변수를 통해 다른 함수의 내부로 전달되는 함수를 콜백 함수(callback function)라고 하며, 매개 변수를 통해 함수의 외부에서 콜백 함수를 전달받은 함수를 고차 함수(Higher-Order Function, HOF)라고 한다.
(출처: 모던 자바스크립트 Deep Dive p. 184)


JavaScript 에서 유용한 배열 고차 함수들을 살펴보자.

filter


배열의 각 요소에 콜백 함수를 적용했을 때 true로 리턴되는 요소들만 구성된 새로운 배열을 리턴한다.

문제. 다음과 같은 배열이 주어졌을 때, 21 이상의 나이를 구해라

const ages = [33, 12, 20, 16, 5, 54, 21, 44, 61, 13, 15, 45, 25, 64, 32];

-반복문 사용

let oldEnough = [];
for (let i = 0; i < ages.length; i++) {
    if (ages[i] >= 21) {
        oldEnough.push(ages[i]);
    }
}

console.log(oldEnough); // [33, 54, 21, 44, 61, 45, 25, 64, 32]

-filter 메서드 사용

let oldEnough = [];
for (let i = 0; i < ages.length; i++) {
    if (ages[i] >= 21) {
        oldEnough.push(ages[i]);
    }
}

console.log(oldEnough); // [33, 54, 21, 44, 61, 45, 25, 64, 32]

-filter 메서드 + 화살표 함수 사용

const oldEnough = ages.filter(age => age >= 21);

console.log(oldEnough);

forEach


forEach 메서드를 사용하면 반복문을 대체할 수 있다.
리턴도 필요하지 않다.

이런 객체를 요소로 한 배열이 주어졌다고 가정해보자.

const companies= [
    {name: "Company One", category: "Finance", start: 1981, end: 2004},
    {name: "Company Two", category: "Retail", start: 1992, end: 2008},
    {name: "Company Three", category: "Auto", start: 1999, end: 2007},
    {name: "Company Four", category: "Retail", start: 1989, end: 2010},
    {name: "Company Five", category: "Technology", start: 2009, end: 2014},
    {name: "Company Six", category: "Finance", start: 1987, end: 2010},
    {name: "Company Seven", category: "Auto", start: 1986, end: 1996},
    {name: "Company Eight", category: "Technology", start: 2011, end: 2016},
    {name: "Company Nine", category: "Retail", start: 1981, end: 1989}
];

-반복문 사용

for (let i = 0; i < companies.length; i++) {
	console.log(companies[i]);    
}

-forEach 메서드 사용 (반복문보다 훨씬 간결하고 편리하다.)

companies.forEach(function(company) {
    console.log(company)
});

-다른 값을 조회할 때도 유용하다.

companies.forEach(function(company) {
    console.log(company.name)
});

map


배열의 각 요소가 콜백 함수의 리턴값으로 이루어진 새로운 배열을 리턴한다.

이런 배열이 주어졌을 때,company name으로 이루어진 새로운 배열을 만들어야 한다면?

const companies= [
    {name: "Company One", category: "Finance", start: 1981, end: 2004},
    {name: "Company Two", category: "Retail", start: 1992, end: 2008},
    {name: "Company Three", category: "Auto", start: 1999, end: 2007},
    {name: "Company Four", category: "Retail", start: 1989, end: 2010},
    {name: "Company Five", category: "Technology", start: 2009, end: 2014},
    {name: "Company Six", category: "Finance", start: 1987, end: 2010},
    {name: "Company Seven", category: "Auto", start: 1986, end: 1996},
    {name: "Company Eight", category: "Technology", start: 2011, end: 2016},
    {name: "Company Nine", category: "Retail", start: 1981, end: 1989}
];

-map 메서드 사용 + 화살표 함수

const companyNames = companies.map(company => company.name);
console.log(companyNames);

-새로운 포맷으로 이루어진 배열을 만들 수도 있다.

const testMap = companies.map(function (company) {
    return `${company.name} [${company.start} - ${company.end}]`
});

console.log(testMap);
// [
//   'Company One [1981 - 2004]',
//   'Company Two [1992 - 2008]',
//   'Company Three [1999 - 2007]',
//   'Company Four [1989 - 2010]',
//   'Company Five [2009 - 2014]',
//   'Company Six [1987 - 2010]',
//   'Company Seven [1986 - 1996]',
//   'Company Eight [2011 - 2016]',
//   'Company Nine [1981 - 1989]'
// ]

sort


sort 메서드를 이용하면 배열을 정렬시킬 수 있다.
기본적으로 오름차순 (ascending order) 으로 정렬된다.

이런 배열이 주어졌을 때, 가장 일찍 창립한 회사 순으로 정렬하려면?

const companies= [
    {name: "Company One", category: "Finance", start: 1981, end: 2004},
    {name: "Company Two", category: "Retail", start: 1992, end: 2008},
    {name: "Company Three", category: "Auto", start: 1999, end: 2007},
    {name: "Company Four", category: "Retail", start: 1989, end: 2010},
    {name: "Company Five", category: "Technology", start: 2009, end: 2014},
    {name: "Company Six", category: "Finance", start: 1987, end: 2010},
    {name: "Company Seven", category: "Auto", start: 1986, end: 1996},
    {name: "Company Eight", category: "Technology", start: 2011, end: 2016},
    {name: "Company Nine", category: "Retail", start: 1981, end: 1989}
];

-sort 메서드 사용

const sortedCompanies = companies.sort(function(company1, company2) {
    if (company1.start > company2.start) {
        return 1;
    } else {
        return -1;
    }
});

console.log(sortedCompanies);
// [
//   { name: 'Company Nine', category: 'Retail', start: 1981, end: 1989 },
//   { name: 'Company One', category: 'Finance', start: 1981, end: 2004 },
//   { name: 'Company Seven', category: 'Auto', start: 1986, end: 1996 },
//   { name: 'Company Six', category: 'Finance', start: 1987, end: 2010 },
//   { name: 'Company Four', category: 'Retail', start: 1989, end: 2010 },
//   { name: 'Company Two', category: 'Retail', start: 1992, end: 2008 },
//   { name: 'Company Three', category: 'Auto', start: 1999, end: 2007 },
//   { name: 'Company Five', category: 'Technology', start: 2009, end: 2014},
//   { name: 'Company Eight', category: 'Technology', start: 2011, end: 2016}
// ]

-sort 메서드 + 삼항연산자(ternary operator) 사용

const sortedCompanies = companies.sort((a, b) => (a.start > b.start ? 1 : -1));

console.log(sortedCompanies);
// 결과는 같다.

reduce


배열의 각 요소를 콜백 함수에 따라서 하나로 누적한 값을 리턴한다. 즉, 하나의 값을 리턴한다.

개인적으로 가장 정의가 난해(?)한 메서드인것 같다. 이해도 어려웠다.. 조금 더 공부하고 정리해서 추가로 작성을 해야겠다.

다음 배열의 각 요소를 모두 더한다면?

const ages = [33, 12, 20, 16, 5, 54, 21, 44, 61, 13, 15, 45, 25, 64, 32];

-반복문 사용

let ageSum = 0;
for (let i = 0; i < ages.length; i++) {
    ageSum += ages[i];
}

console.log(ageSum);
// 460

-reduce 메서드 사용

const ageSum = ages.reduce(function(total, age) {
    return total + age;
}, 0);

console.log(ageSum);
// 460

-reduce 메서드 + 화살표 함수

const ageSum = ages.reduce((total, age) => total + age, 0);

console.log(ageSum); 
// 460



References

profile
FE Developer 매일 한 걸음씩!

0개의 댓글