...
자바스크립트 배열 고차함수
여러분이 자바스크립트를 배우는 중이라면, 고차 함수(Higher-Order Function) 라는 용어를 얼핏 들어본 적이 있을 것이다.
고차 함수란, 함수를 파라미터로 전달받거나 연산의 결과로 반환해주는 메서드를 일컫는다. 요즘 자주 거론되는 함수형 프로그래밍의 핵심이기도 하며, 자바스크립트를 함수형 프로그래밍에 알맞은 언어로 만들어주는 특성이기도 하다.
함수형 프로그래밍이란?
함수형 프로그래밍은 함수를 다른 함수의 파라미터로 넘길 수도 있고 반환(return) 값으로 함수를 받을 수도 있는 프로그래밍 형태를 말한다. 함수형 프로그래밍에서, 개발자는 함수라는 용어 하에서 생각하고 코딩하게 된다.
이번 시간에는 자바스크립트에서 광범위 하게 사용되는 배열의 고차함수를 총정리 해보는 시간을 가져 보겠다. 똑같이 배열을 순회한다는 점에서 이들은 모두 비슷하지만 리턴하는 결과가 각기 다르니 이를 유심히 보며 익히는 것을 권한다.
.forEach()
for문을 대체하는 고차 함수.- 반복문을 추상화하여 구현된 메서드이고 내부에서 주어진 배열을 순회하면서 연산을 수행
const numberArr = [1, 2, 3, 4, 5];
let total = 0;
numberArr.forEach((item) => {
total += item;
});
console.log(total); // 15
.map()
forEach같이 순회하면서, 콜백함수에서의 실행결과를 리턴한 값으로 이루어진 배열을 만들어 반환
const numberArr = [1, 2, 3, 4, 5];
const numberMapArr = numberArr.map((item) => {
return (item % 2 === 0) ? 'even' : 'odd'; // 연산한 결과값을 넣어 배열 반환
});
console.log(numberMapArr); // ['odd', 'even', 'odd', 'even', 'odd']
[ forEach와 map의 차이 ]
두 메서드 모두 배열을 순회하는 것은 동일하지만,forEach()의 경우 각 요소를 참조한 연산이 이루어지고map()의 경우엔 각 요소를 다른 값으로 맵핑한 새로운 배열이 반환되는 점에 차이가 있다.
정리하면forEach()는 for문을 대체하여 사용하고map()은 연산의 결과로 새로운 배열을 생성하고자할 때 사용된다.
.find()
indexOf()가 찾고자 하는 값을 인덱스로 주는거고,include()가 찾고자 하는 값을 Bool로 주는거면,find()는 찾고자 하는 값을 그대로 반환한다- 주어진 배열을 순회하면서 콜백 함수 실행의 반환값이 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 => {
return item.age === 20 // 해당조건에 부합하면 item값 반환
}); // {name: "Harry", age: 20}
// find는 하나만 찾음. 뒤에서 배울 filter은 여러개를 배열로
console.log(numberArr.find(item => item === 3)); // 3
console.log(numberArr.filter(item => item === 3)); // [3, 3]
.findIndex()
- 배열 메소드
indexOf()의 콜백함수 버젼. - 고차함수
find()의 리턴값이 인덱스인 버젼.
const objectArr = [
{ name: 'Harry', age: 20 },
{ name: 'Kim', age: 30 },
{ name: 'Steve', age: 40 }
];
console.log(objectArr.findIndex(item => {
return item.age === 20 // 해당조건에 부합하면 item의 인덱스를 반환
}); // 0
console.log(objectArr.findIndex(item => item.name === 'Kim')); // 1
.filter()
- 주어진 배열을 순회하면서 콜백 함수의 반환값이 true에 해당하는 요소로만 구성된 새로운 배열을 생성하여 반환.
- 한마디로
find()의 찾아서 값을 반환하는 기능과map()의 배열 생성 기능의 융합 버젼.
const numberArr = [1, 2, 3, 4, 5];
const numberFilterArr = numberArr.filter((item) => {
return item % 2 === 0; // 해당조건에 부합으면 item을 넣어 배열 반환
});
console.log(numberFilterArr); // [2, 4]
.reduce()
- 콜백 함수의 실행된 반환값(initialValue)을 전달 받아 연산의 결과값이 반환.
- 첫번째 인자(accumulator)서부터 시작해서 배열값인 두번째 인자(currentvalue) 을 순회하며
accumulator+=currentvalue을 실행. - 사실상
forEach,map,filter기능을reduce로 모두 구현해서 쓸순 있어 고차함수의 부모라고 불림
reduce()함수 호출시 initialValue 값이 없는 경우
- accumulator : 배열의 첫번째 값
- currentValue : 배열의 두번째 값
reduce()함수 호출시 initialValue 값이 있는 경우
- accumulator : initialValue가 지정한 값
- currentValue : 배열의 첫번째 값
const numberArr = [1, 2, 3, 4, 5];
const sum = numberArr.reduce((previousValue, currentValue, currentIndex, thisArray) => {
console.log('Current Index: ' + currentIndex + ' / Previous Value: ' + previousValue + ' / Current Value: ' + currentValue);
return previousValue + currentValue; // 연산한 결과값을 누산기previousValue에 넣어 최종값을 얻는다.
}, 0);
console.log('Sum: ' + sum);
/*
Current Index: 0 / Previous Value: 0 / Current Value: 1
Current Index: 1 / Previous Value: 1 / Current Value: 2
Current Index: 2 / Previous Value: 3 / Current Value: 3
Current Index: 3 / Previous Value: 6 / Current Value: 4
Current Index: 4 / Previous Value: 10 / Current Value: 5
Sum: 15
*/
호출 순서 | previousValue | currentValue | currentIndex | thisArray | 콜백 함수 반환값 |
1 | 0 | 1 | 0 | [1, 2, 3, 4, 5] | 1 |
2 | 1 | 2 | 1 | [1, 2, 3, 4, 5] | 3 |
3 | 3 | 3 | 2 | [1, 2, 3, 4, 5] | 6 |
4 | 6 | 4 | 3 | [1, 2, 3, 4, 5] | 10 |
5 | 10 | 5 | 4 | [1, 2, 3, 4, 5] | 15 |
.sort()
- 배열 정렬.
- 단, 복사본이 만들어지는게 아니라 원 배열이 정렬됨.
- 콜백 함수를 통해 배열의 원소들을 어느 기준으로 정렬할지 지정해야함 (번거로움)
var arr = ['red', 'blue', 'green', 'white', 'black'];
arr.sort(); // [ 'black', 'blue', 'green', 'red', 'white' ]
위와 같이 문자를 정렬할때는 문제가 없지만, 숫자를 정렬하는 경우에도 ABC 순으로 정렬이 되기 때문에 콜백함수를 넣어 조작이 필요하다.
아래와 같이, 콜백함수에서 인자 두개를 받아, 두 수의 차가 양수값(큰값)이냐 음수값(작은값)이냐를 이용하여 정렬한다.
var arr2 = [1,2,3,10,50,70,8,4];
arr2.sort(); // [ 1, 10, 2, 3, 4, 50, 70, 8 ]
arr2.sort(function(a, b) {
console.log(a,b);
});
/*
10 1
2 10
3 2
4 3
50 4
70 50
8 70
*/
arr.sort(function(a, b) {
if(a > b) return 1;
if(a === b) return 0;
if(a < b) return -1;
}); // [ 1, 2, 3, 4, 8, 10, 50, 70 ]
📌 숫자 정렬
const arr = [2, 1, 3, 10];
arr.sort(function(a, b) {
return a - b;
}); // [1, 2, 3, 10] 오름차순
arr.sort(function(a, b) {
return b - a;
}); // [10, 3, 2, 1] 내립차순
📌 문자 정렬
const arr = ['banana', 'b', 'boy'];
arr.sort(); // ['b', 'banana', 'boy']
arr.sort(function(a, b) {
if(a < b) return 1;
if(a > b) return -1;
if(a === b) return 0;
}); // ['boy', 'banana', 'b'] 내림차순
📌 문자(대소문자 구분없이) 정렬
const arr = ['banana', 'b', 'Boy'];
arr.sort(); // ['Boy','b','banana']
// sort() 함수로 문자열을 정렬하면, 대문자가 소문자보다 앞에 오도록 정렬이 됩니다.
// 유니코드가 대문자가 소문자보다 앞서기 때문입니다.
arr.sort(function(a, b) {
const upperCaseA = a.toUpperCase();
const upperCaseB = b.toUpperCase();
if(upperCaseA > upperCaseB) return 1;
if(upperCaseA < upperCaseB) return -1;
if(upperCaseA === upperCaseB) return 0;
}); // ['b', 'banana', 'Boy'] 오름차순
arr.sort(function(a, b) {
const upperCaseA = a.toUpperCase();
const upperCaseB = b.toUpperCase();
if(upperCaseA < upperCaseB) return 1;
if(upperCaseA > upperCaseB) return -1;
if(upperCaseA === upperCaseB) return 0;
}); // ['Boy', 'banana', 'b'] 내림차순
📌 객체 정렬
const arr = [
{name: 'banana', price: 3000},
{name: 'apple', price: 1000},
{name: 'orange', price: 500}
];
arr.sort(function(a, b) {
return a.price - b.price; // price 숫자값을 기준으로 정렬
});
/*
{"name":"orange","price":500}
{"name":"apple","price":1000}
{"name":"banana","price":3000}
*/
.some()
- 배열 메소드인
include()의 콜백함수 버전. include는 값이 있냐에 따른 bool이면,some은 함수의 로직에 따른 bool.- 배열의 요소들을 주어진 함수(조건)을 통과하는데 한개라도 통과되면 true, 아닐때에는 false를 출력.
- 빈 배열로 함수(조건)을 통과하면 무조건 false를 출력.
- 이와같이 some이라는 이름은, 함수(조건)에 부합한 갯수가 some이면 true라는 뜻에서 비롯됨.
const array = [1, 3, 5];
// 짝수인지 체크
const result = array.some((currentValue) => {
return currentValue % 2 === 0;
})
console.log(result); // 리턴 값 : false
// 그 이유는 array의 3개의 요소 모두 2로 나눌때 나머지가 0이 아니기 때문이다.
// 하나라도 부합한 조건에 맞으면 true, 모두 부합하지 않으면 false
// -----------------------------------------------
const array2 = [1, 2, 3, 5];
const result2 = array2.some((currentValue) => {
return currentValue % 2 === 0;
})
console.log(result2); // 리턴 값 : true
// 그 이유는 array의 4개의 요소 모두 2로 나눌때 나머지가 0인 요소가 하나라도 있기 때문이다.
// 하나라도 부합한 조건에 맞으면 true, 모두 부합하지 않으면 false
.every()
some()의 반대 버전- 배열안의 모든 요소가 주어진 함수(조건)을 모두 통과하면 true, 한 요소라도 통과하지 못하면 false를 출력.
- 빈 배열을 함수에 적용시키면 무조건 true를 반환.
- 이와같이 every이라는 이름은, 함수(조건)에 부합한 갯수가 every이면 true라는 뜻에서 비롯됨.
const array = [1, 30, 39, 29, 13];
const result = array.every((currentValue) => {
return currentValue < 40;
})
console.log(result); // 리턴 값 : true
// 그 이유는 array의 모든 요소가 40보다 작기 때문이다.
// 하나라도 부합한 조건에 맞지 안으면 false, 모두 부합하면 true
// -----------------------------------------------
const array2 = [1, 30, 39, 29, 100, 13];
const result2 = array2.every((currentValue) => {
return currentValue < 40;
})
console.log(result2); // 리턴 값 : false
// 그 이유는 array의 1개의 요소 100이 40보다 크기 때문이다.
// 하나라도 부합한 조건에 맞지 안으면 false, 모두 부합하면 true
# 참고자료
인용한 부분에 있어 만일 누락된 출처가 있다면 반드시 알려주시면 감사하겠습니다
이 글이 좋으셨다면 구독 & 좋아요
여러분의 구독과 좋아요는
저자에게 큰 힘이 됩니다.