Section 7. 자바스크립트 고차함수 메서드들
배열의 고차함수 higher order function 메서드의 특징들은 다음과 같다
- 다른 함수(콜백 함수)를 인자로 받는다.
- 함수형 프로그래밍 - 변수 사용 없이 순회 작업들을 코딩한다.
1. forEach - 각 요소를 인자로 콜백함수를 실행하는 메서드
- for문의 좋은 대체제이다.
- 단점은 예외를 던지지 않으면 종료할 수 없다. - break, continue 사용이 불가하다.
인자들 :
- 콜백함수 - 인자 : (현재 값, 현재 값의 인덱스, 해당 배열)
- thisArg
등등이 있다.
const arr = [1, 2, 3, 4, 5];
const result = arr.forEach(itm => {
console.log(itm);
});
//1
//2
//3
//4
//5
콜백함수를 인자로 받았고 forEach를 사용해서 출력이 된 모습이다. 그런데 result자체는 undefined를 반환한다.
// 💡 결과로는 undefined 반환 - 실행 자체를 위한 메서드
console.log('반환값:', result); //반환값: undefined
여기서 forEach는 어떤 작업을 콜백으로 수행하기 위해서 존재한거지 값을 반환한 것이 아니기 때문에 그렇다.
실제 배열을 선언하고 그것으로 작업을 수행하고 결과를 살펴보면 다음과 같다.
const arr = [1, 2, 3, 4, 5];
// 현존하는 함수를 인자로 - 💡 결과 살펴볼 것
arr.forEach(console.log);
//1 0 (5) [1, 2, 3, 4, 5]
//2 1 (5) [1, 2, 3, 4, 5]
//3 2 (5) [1, 2, 3, 4, 5]
//4 3 (5) [1, 2, 3, 4, 5]
//5 4 (5) [1, 2, 3, 4, 5]
이처럼 값이 3가지가 출력이 된다. 첫 번째값은 바로 현재값이다. 두 번째는 현재 값의 인덱스이다. 마지막은 해당 배열이 되겠다.
이렇게 console.log 함수를 인자로 넣어버리면 위와 같이 멋대로 3개의 값들이 출력된다. 따라서 forEach를 제대로 쓰려면 콜백함수를 무엇을 쓸 것인지 정확히 해야 한다.
const arr = [10, 20, 30, 40, 50];
// 콜백함수의 인자가 둘일 때
arr.forEach((itm, idx) => {
console.log(itm, idx);
});
//10 0
//20 1
//30 2
//40 3
//50 4
그러면 위의 예시를 이용해서 이렇게 활용할 수 있다.
const logWithIndex = (itm, idx) => {
console.log(`[${idx}]: ${itm}`);
}
arr.forEach(logWithIndex);
//[0]: 10
//[1]: 20
//[2]: 30
//[3]: 40
//[4]: 50
2. map - 각 요소를 주어진 콜백함수로 처리한 새 배열을 반환하는 메서드
각 요소를 받아서 어떤 기준으로 그 값을 처리한 다음 각각 기준대로 반환하는 것이다.
인자들 :
- 콜백함수 - 인자: (현재 값, 현재 값의 인덱스, 해당 배열)
- thisArg
const orgArr = [1, 2, 3, 4, 5];
// ⭐️ 각 콜백함수는 어떤 값을 반환해야 함
const arr1 = orgArr.map(i => i + 1);
const arr2 = orgArr.map(i => i * i);
const arr3 = orgArr.map(i => i % 2 ? '홀수' : '짝수');
console.log(arr1); //(5) [2, 3, 4, 5, 6]
console.log(arr2); //(5) [1, 4, 9, 16, 25]
console.log(arr3); //(5) ['홀수', '짝수', '홀수', '짝수', '홀수']
여기서 각 콜백함수는 어떤 값을 반환해야 한다는 것을 명심하자.
그리고 원본이 수정되지 않는다. 새로운 배열을 만드는 것이기 때문이다.
다른 예시를 보면
const orgArr = [
{ name: '사과', cat: '과일', price: 3000 },
{ name: '오이', cat: '채소', price: 1500 },
{ name: '당근', cat: '채소', price: 2000 },
{ name: '살구', cat: '과일', price: 2500 },
{ name: '피망', cat: '채소', price: 2500 },
{ name: '딸기', cat: '과일', price: 5000 }
];
const arr1 = orgArr.map(itm => {
// 💡 블록 안에서는 return 문 필요함
return {
name: itm.name,
cat: itm.cat
}
});
console.log(arr1);
블럭 안에서는 꼭 return문을 사용해야 한다. 이유는 콜백함수는 값을 반드시 반환해야 하기 때문이다.
3. find, findLast, findIndex, findLastIndex - 주어진 기준으로 검색하는 메서드
콜백함수로 인자로 넣었을 때 true를 반환하는 것들은 다음과 같다
- find - 첫 번째 값 반환
- findLast - 마지막 값 반환
- findIndex - 첫 번째 값의 인덱스 반환
- findLastIndex - 마지막 값의 반환
공통 인자들 :
- 콜백함수 - 인자 : (현재 값, 현재 값의 인덱스, 해당 배열)
- thisArg
const arr = [1, 2, '삼', 4, 5, 6, '칠', 8, 9];
const isString = i => typeof i === 'string';
const isBoolean = i => typeof i === 'boolean';
console.log(
arr.find(isString),
arr.findLast(isString),
arr.findIndex(isString),
arr.findLastIndex(isString)
); //삼 칠 2 6
만약 없을 경우 값은 undefined, 인덱스는 -1을 반환한다.
// 없을 시 값은 undefined, 인덱스는 -1 반환
console.log(
arr.find(isBoolean),
arr.findLast(isBoolean),
arr.findIndex(isBoolean),
arr.findLastIndex(isBoolean)
); //undefined undefined -1 -1
4. some, every - 어떤/모든 요소가 기준을 충족하는지 확인
콜백함수에 인자로 넣은
- some - 요소들 중 하나라도 true를 반환하는가 여부를 반환하는 메서드
- every - 모든 요소가 true를 반환하는가 여부를 반환하는 메서드
인자들 :
- 콘백함수 - 인자 : (현재 값, 현재 값의 인덱스, 해당 배열)
- thisArg
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
console.log(
arr.some(i => i % 2),
arr.every(i => i % 2),
arr.some(i => i < 0),
arr.every(i => i < 10)
); //true false false true
5. filter - 주어진 기준을 충족하는 요소들로 새 배열을 만들어서 반환하는 메서드
원본 배열을 수정하지 않는다.
인자들 :
- 콜백함수 - 인자 : (현재 값, 현재 값의 인덱스, 해당 배열)
- thisArg
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
const odds = arr.filter(i => i % 2);
const evens = arr.filter(i => !(i % 2));
const largerThan3 = arr.filter(i => i > 3);
console.log(odds); //[1, 3, 5, 7, 9]
console.log(evens); //[2, 4, 6, 8]
console.log(largerThan3); //[4, 5, 6, 7, 8, 9]
6. reduce, reduceRight
주어진 콜백함수에 따라 값들을 접어 나가는 메서드
인자들 :
- 콜백함수 - 인자 : (이전값, 현재값, 현재 인덱스, 해당 배열)
- 초기화 값
초기화 값이 없을 때 - 첫 번째와 두 번째 값부터
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
console.log(
arr.reduce((prev, curr, idx) => {
console.log(`p: ${prev}, c: ${curr}, i: ${idx}`);
return prev + curr;
})
);
출력문은 다음과 같다
이렇게 초기화 값이 없을 때는 현재값 curr에 arr의 두 번째 값인 2가 들어간 것을 알 수 있다. (prev에는 첫 번째 값인 1이 들어갔다). 현재 인덱스 값도 1임을 볼 수 있다.
첫 번째 출력문에서 reduce를 통해 prev + curr 해서 3이 반환되었다.
두 번째 출력문에서 반환된 3이 prev에 들어갔고 arr에서 2 다음 값인 3이 curr에 대입된 것을 볼 수 있다. 결과는 6반환.
세 번째 출력문에서 6이 prev에, 그리고 arr에서 3 다음 값인 4가 들어갔다.
reduce 메서드는 이런 식으로 콜백함수를 통해 하나하나씩 접어 가는 것을 볼 수 있다.
초기화 값이 있을 때의 경우는 다음과 같다
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
console.log(
arr.reduce((prev, curr, idx) => {
console.log(`p: ${prev}, c: ${curr}, i: ${idx}`);
return prev + curr;
}, 10)
);
초기화 값 10이 들어갔고 인덱스는 0부터 시작한다는 것을 알고 넘어가자.
reduceRight는 시작 방향이 오른쪽인 메서드이다.
const arr = ['가', '나', '다', '라', '마', '바', '사'];
console.log(
arr.reduceRight((prev, curr, idx) => {
console.log(`p: ${prev}, c: ${curr}, i: ${idx}`);
return prev + curr;
})
);
출력문을 확인해보면 알 수 있다.
7. sort - 배열을 (주어진 기준대로) 정렬하는 메서드
- 배열 자체의 순서를 바꾼다 - 원본 수정
- 해당 배열을 반환한다
인자들 :
콜백함수 (필수는 아니다) - 인자 : (앞의 값, 뒤의 값)
1. 인자가 없을 경우는 다음과 같다
const arr = ['라', '사', '다', '가', '바', '마', '나'];
arr.sort();
console.log(arr); //['가', '나', '다', '라', '마', '바', '사']
인자가 없을 경우 기본적으로 오름차순으로 정렬이 되는 것을 볼 수 있다.
let randomWord = 'DBKGICAHFEJ';
console.log(
randomWord
.split('')
.sort()
.join('')
); //ABCDEFGHIJK
console.log(randomWord); //DBKGICAHFEJ
이번에는 sort를 썼는데도 원본은 바뀌지 않았다.
이유는 split을 사용하면 randomWord가 별도의 배열로 반환되기 때문이다. 그리고 그 배열에다 sort를 했으니 원본은 바뀐것이 없게 되는 것이다.
만약 숫자를 sort하는 경우는 다음과 같다
const arr = [1, 2, 30, 400, 10, 100, 1000];
console.log(arr.sort()); //[1, 10, 100, 1000, 2, 30, 400]
숫자일 경우 오름차순으로 정렬이 되지 않는 것을 볼 수 있다.
이유는 숫자일 경우 문자열로 암묵적 변환하여 오름차순으로 정렬하기 때문이다.
정확한 정렬을 위해 - 콜백 함수를 사용
- 두 인자 a와 b: 인접한 두 요소
- 0보다 큰 값 반환 : b를 앞으로 - 순서 뒤집는다
- 0 반환 : 순서 유지 - ECMAScript 표준은 아니므로 환경마다 다를 수 있다
- 0보다 작은 값 반환 : a를 앞으로 - 사실상 순서 유지다
8. flatMap - map 한 다음 flat 매핑해서 펼치는 메서드
인자들 :
- 콜백함수 - 인자: (현재 값, 현재 값의 인덱스, 해당 배열)
- thisArg
const arr = [1, 2, 3, 4, 5];
console.log(
arr.map(i => [i, i, i])
);
그냥 map 매서드를 사용했을 때의 출력문은 다음과 같다
이것을 flat한 것을 flatMap이라고 하는 것이다.
console.log(
arr.flatMap(i => [i, i, i])
); //(15) [1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5]
먼저 map한 결과에 flat이 적용된 것을 볼 수 있다.