JavaScript
20210712 JavaSciprt DeepDive 10 : 배열 고차 함수, sort, forEach, map, filter, reduce, some, every, find, findIndex, flatMap
JavaScript Deep Dive 10
용어 및 중요사항 정리
배열 고차 함수 | 표시 | Callback | return |
---|---|---|---|
sort | Array.prototype.sort(comparisonCallback) |
음수(첫 인수), 양수(두번째 인수), 0(정렬X) |
정렬된 배열을 반환 |
forEach | Array.prototype.forEach(Callback, bindThis) |
Callback(value, index, array) | undefined |
map | Array.prototype.map(Callback, bindThis) |
Callback(value, index, array | 새로운 배열을 반환 |
filter | Array.prototype.filter(Callback, bindThis) |
Callback(value, index, array) | 콜백함수의 반환값이 true인 요소로만 구성된 새로운 배열을 반환 |
reduce | Array.prototype.reduce(Callback, FirstAccumulator) |
Callback(accumulator, currentValue, index, array) | 제일 마지막 Callback 결과값을 만들어 반환 |
some | Array.prototype.some(Callback, bindThis) |
Callback(value, index, array) | 콜백함수의 반환값이 한번이라도 참이면 true, 모두 거짓이면 false 반환 |
every | Array.prototype.every(Callback, bindThis) |
Callback(value, index, array) | 콜백함수의 반환값이 모두 참이면 true 반환, 한번이라도 거짓이면 false |
find | Array.prototype.find(Callback, bindThis) |
Callback(value, index, array) | Callback 반환값이 true인 첫번째 요소를 반환 |
findIndex | Array.prototype.findIndex(Callback, bindThis) |
Callback(value, index, array) | Callback 반환값이 true인 첫번째 요소의 인덱스를 반환 |
flatMap | Array.prototype.flatMap(Callback, bindThis) |
Callback(value, index, array) | Callback으로 처리된 map 배열에서 평탄화된 새로운 배열을 반환 |
배열
배열 고차 함수
고차 함수
: 외부 상태의 변경이나 가변 데이터를 피하고 불변성을 지향하는 함수형 프로그래밍 기반함수형 프로그래밍
: 순수 함수와 보조 함수를 통해 조건문과 반복문을 제거하여 복잡성 해결하고 변수의 사용을 억제하여 상태 변경을 피하려는 프로그래밍 패러다임
Array.prototype.sort
Array.prototype.sort(comparisonCallback)
- 배열의 요소를 콜백 비교함수 기준으로 정렬함 (한글 문자열도 가능)
return
: 정렬된 배열을 반환comparisonCallback
: 요소들의 비교 기준이 되는 콜백함수 (숫자의 경우 유니코드 코드 포인트로 정렬시 문제가 생겨서 비교함수를 사용)- 비교함수의 return 값이
음수
-> 비교함수의 첫번째 인수를 우선 정렬 - 비교함수의 return 값이
0
-> 정렬하지 않음 - 비교함수의 return 값이
양수
-> 비교함수의 두번째 인수를 우선 정렬a, b => a - b
: 오름차순a, b => b - a
: 내림차순
- 객체 요소의 정렬은, 숫자 연산자가 작용되지 않으므로 삼항연산자로 음수, 양수, 0을 지정해줘야 함
- 비교함수의 return 값이
- 비교함수 콜백이 생략된 경우, 기본적인 오름차순으로 정렬
- 문자 정렬
- 내림차순 정렬 :
sort 후 reverse 메서드
사용 - 원본 배열을 직접 변경
- 내림차순 정렬 :
- 유니코드 코드 포인트 순서를 따름 (숫자의 경우 일시적으로 문자열로 바꾸어 정렬하여 비교함수 필요)
- 내부적으로 Timsort 알고리즘을 사용함(Mergesort의 최적화 버전)
// 문자 정렬
const strings = ["C", "B", "A"];
// 오름차순: sort
strings.sort();
// ['A', 'B', 'C']
// 내림차순: sort 후 reverse
strings.revese();
// ['C', 'B', 'A']
// 숫자 정렬
const points = [40, 100, 1, 5, 2, 25, 10];
points.sort((a, b) => a - b);
console.log(points); // [1, 2, 5, 10, 25, 40, 100]
console.log(`최소값 ${points[0]}, 최대값 ${points[points.length - 1]}`); // 최소값 1 , 최대값 100
points.sort((a, b) => b - a);
console.log(points); // [100, 40, 25, 10, 5, 2, 1]
console.log(`최대값 ${points[0]}, 최소값 ${points[points.length - 1]}`); // 최대값 100, 최소값 1
// 객체 정렬
const todos = [
{ id: 4, content: "JS" },
{ id: 1, content: "HTML" },
{ id: 2, content: "CSS" },
];
function compare(key) {
return (a, b) => (a[key] > b[key] ? 1 : a[key] < b[key] ? -1 : 0);
}
todos.sort(compare("id"));
console.log(todos);
/*
[
{ id: 1, content: "HTML" },
{ id: 2, content: "CSS" },
{ id: 4, content: "JS" },
]
*/
todos.sort(compare("content"));
console.log(todos);
/*
[
{ id: 2, content: "CSS" },
{ id: 1, content: "HTML" },
{ id: 4, content: "JS" },
]
*/
Array.prototype.forEach
Array.prototype.forEach(Callback, bindThis)
- 내부에서 반복문을 통해 자신을 호출한 배열을 순회하면서 수행해야 할 처리를 콜백 함수로 전달받아 반복 호출
return
: undefinedCallback(value, index, array)
: 요소의 값, 인덱스, 배열 자체(this)를 인수로 전달 받아 작업을 처리- break, continue 문을 사용할 수 없음
- 희소 배열의 경우 존재하지 않는 요소는 순회 대상에서 제외 (for문은 희소배열을 undefined로 순회함)
- bindThis : 콜백함수 내부에서 사용할 This를 특정하여 객체 전달할 수 있음
- for문을 대체할 수 있는 고차 함수
- 원본 배열을 변경하지 않음
- array인 this 인수를 활용하면 원본 배열을 직접 변경할 수 있음
콜백 함수 내부에서 this 사용시
- 클래스의 forEach 콜백에서 사용한 경우 -> this = undefined (콜백 함수가 일반함수로 호출되고 strict mode이기 때문)
- 생성자 함수, 함수 표현식인 콜백에서 사용 -> this = window 전역 객체 (콜백 함수가 일반 함수로 호출되기 때문)
- 화살표 함수인 콜백 내부에서 사용 -> this = 상위 스코프의 this
폴리필 polyfill
: 최신 사양의 기능을 지원하지 않는 브라우저를 위해 누락된 최신 사양의 기능을 구현하여 추가하는 것
if (!Array.prototype.forEach) {
Array.prototype.forEach = function (callback, thisArg) {
if (typeof callback !== "function") {
throw new TypeError(callback + "is not a function");
}
thisArg = thisArg || window;
for (var i = 0; i < this.length; i++) {
callback.call(thisArg, this[i], i, this);
}
};
}
for vs forEach
비교 | for | forEach |
---|---|---|
break, continue 문 | O | X |
가독성 | forEach보다 낮음 | 높음 |
성능 | 높음 | for보다 낮음 |
희소배열 | undefined로 순회 | 순회대상에서 제외 |
Array.prototype.map
Array.prototype.map(Callback, bindThis)
- 자신을 호출한 배열의 모든 요소를 순회하면서 인수로 전달받은 콜백 함수를 반복 호출
return
: 콜백 함수의 반환값들로 구성된 새로운 배열을 반환Callback(value, index, array)
: 요소의 값, 인덱스, 배열 자체(this)를 인수로 전달 받아 작업을 처리- bindThis : 콜백함수 내부에서 사용할 This를 특정하여 객체 전달할 수 있음
- 원본 배열은 변경되지 않음
- 원본 배열의 length 프로퍼티 값 === 새로운 배열의 length 프로퍼티 값
콜백 함수 내부에서 this 사용시(forEach와 동일함)
- 클래스의 map 콜백에서 사용한 경우 -> this = undefined (콜백 함수가 일반함수로 호출되고 strict mode이기 때문)
- 생성자 함수, 함수 표현식인 콜백에서 사용 -> this = window 전역 객체 (콜백 함수가 일반 함수로 호출되기 때문)
- 화살표 함수인 콜백 내부에서 사용 -> this = 상위 스코프의 this
Array.prototype.filter
Array.prototype.filter(Callback, bindThis)
- 자신을 호출한 배열의 모든 요소를 순회하면서 인수로 전달받은 콜백 함수를 반복 호출
Callback(value, index, array)
: 요소의 값, 인덱스, 배열 자체(this)를 인수로 전달 받아 작업을 처리- bindThis : 콜백함수 내부에서 사용할 This를 특정하여 객체 전달할 수 있음
return
: 콜백함수의 반환값이 true인 요소로만 구성된 새로운 배열을 반환사용되는 상황
- 필터링 조건을 만족하는 특정 요소만 추출하여 새로운 배열을 만들고 싶을 때 사용
- 원본 배열에서 특정 요소를 제거하기 위해 사용 가능 (중복 요소들 제거 가능)
- 특정요소가 아닌것을 조건으로 넣어 특정 요소가 아닌것만 모아 원본 배열에 재할당 -> 특정요소가 없는 원본배열
- 특정요소가 하나만 제거시 -> indexOf + splice
- 원본 배열은 변경되지 않음
- 원본 배열의 length 프로퍼티 값 >= 새로운 배열의 length 프로퍼티 값
콜백 함수 내부에서 this 사용시(forEach, map와 동일함)
- 클래스의 map 콜백에서 사용한 경우 -> this = undefined (콜백 함수가 일반함수로 호출되고 strict mode이기 때문)
- 생성자 함수, 함수 표현식인 콜백에서 사용 -> this = window 전역 객체 (콜백 함수가 일반 함수로 호출되기 때문)
- 화살표 함수인 콜백 내부에서 사용 -> this = 상위 스코프의 this (추천)
Array.prototype.reduce
Array.prototype.reduce(Callback, FirstAccumulator)
- 자신을 호출한 배열을 모든 요소를 순회하며 인수로 전달받은 콜백 함수를 반복 호출
- 콜백 함수의 반환값(Callback Return)을 다음 순회시에 콜백 함수의 첫번째 인수(accumulator)로 전달하여 콜백함수 호출함
Callback(accumulator, currentValue, index, array)
return
: 제일 마지막 Callback 결과값을 만들어 반환- FirstAccumulator를 항상 명시적으로 적어 초기값을 전달해 주는게 안전함
- 빈 배열인 경우에도 Error를 발생시키지 않음
- 원본배열 변경 없음
// 평균 구하기
const values = [1, 2, 3, 4, 5, 6];
const average = values.reduce((acc, cur, i, { length }) => {
// 마지막 인덱스에서 평균을 구하고, 그전까지의 인덱스는 계속 합침
return i === length - 1 ? (acc + cur) / length : acc + cur;
}, 0);
// 최대값 구하기
const max = values.reduce((acc, cur) => (acc > cur ? acc : cur), 0);
const mathMax = Math.max(...values);
// 요소별 중복 횟수 구하기
const alphabet = ["a", "c", "k", "c", "d", "l", "c", "a", "h", "g"];
const count = alphabet.reduce((acc, cur) => {
// acc에 cur에 해당하는 프로퍼티가 없으면 동적으로 생성해서 1을 할당
// cur에 해당하는 프로퍼티가 있으면 거기에 1을 더함
acc[cur] = (acc[cur] || 0) + 1;
return acc;
}, {});
// 중첩 배열 평탄화
const nestingArray = [1, [2, 3], 4, [5, 6]];
const flatten = nestingArray.reduce((acc, cur) => acc.concat(cur), []);
const flat = nestingArray.flat(1);
// 중복 요소 제거
const duplicateValues = [1, 2, 1, 3, 5, 4, 5, 3, 4, 4];
// reduce 방식
const result = duplicateValues.reduce((acc, cur, i, arr) => {
// 앞에서 부터 처음에 찾은 값이면 넣고, 아니면 안넣고
if (arr.indexOf(cur) === i) acc.push(cur);
return acc;
}, []);
// filter 방식
const result = duplicateValues.filter((v, i, arr) => arr.indexOf(v) === i);
// Set 집합 방식
const result = [...new Set(duplicateValues)];
Array.prototype.some
Array.prototype.some(Callback, bindThis)
- 자신을 호출한 배열의 요소를 순회하면서 인수로 전달된 콜백 함수를 호출
Callback(value, index, array)
return
: 콜백함수의 반환값이 한번이라도 참이면 true, 모두 거짓이면 false 반환- 원본 배열이 빈 배열인 경우 언제나 false 반환
Array.prototype.every
Array.prototype.every(Callback, bindThis)
- 자신을 호출한 배열의 요소를 순회하면서 인수로 전달된 콜백 함수를 호출
Callback(value, index, array)
return
: 콜백함수의 반환값이 모두 참이면 true 반환, 한번이라도 거짓이면 false- 원본 배열이 빈 배열인 경우 언제나 true 반환
Array.prototype.find
Array.prototype.find(Callback, bindThis)
- 자신을 호출한 배열의 요소를 순회하면서 인수로 전달된 콜백 함수를 호출
Callback(value, index, array)
return
: Callback 반환값이 true인 첫번째 요소를 반환- 콜백 함수의 반환값이 true가 없으면 undefined 반환
- find의 결과는 항상 요소값
Array.prototype.findIndex
Array.prototype.findIndex(Callback, bindThis)
- 자신을 호출한 배열의 요소를 순회하면서 인수로 전달된 콜백 함수를 호출
Callback(value, index, array)
return
: Callback 반환값이 true인 첫번째 요소의 인덱스를 반환- 콜백 함수의 반환값이 true가 없으면 -1 반환
Array.prototype.flatMap
Array.prototype.flatMap(Callback, bindThis)
- map메서드를 통해 생성된 새로운 배열을 평탄화함 (map + flat)
Callback(value, index, array)
return
: Callback으로 처리된 map 배열에서 평탄화된 새로운 배열을 반환- 1단계 평탄화만 함