배열의 reduce() 함수에 대해 정리해보려고 한다.
내용은 MDN 웹 문서 사이트를 참고하여 정리된 내용이며, 더 많은 예제와 자세한 내용은 아래 링크에서 볼 수 있다.
링크로 가기 👉 Array.prototype.reduce()
reduce()
reduce()
메서드는 배열에 대하여 주어진 리듀서(reducer)함수를 실행하고 결과 값을 반환한다.
reduce()는 reduce(콜백함수, 초기값)와 같은 형태를 가지고 있으며, 배열의 각 요소가 주어진 콜백함수를 거치게 된다. 이 콜백함수를 리듀서(reducer) 라고 한다.
리듀서는 네가지 인자를 가진다.
- accumulator(누산기): 누산기는 콜백(리듀서)의 반환 값을 누적한다. 만약 초기값이 제공된다면, 리듀서의 첫번째 호출 시 accumulator의 값은 초기값과 같다. 만약 초기값이 제공되지 않는다면 accumulator는 배열의 첫번째 값이 자동으로 들어가게된다.
- currentValue: 현재 처리할 요소이다.
- currentIndex(optional): 처리할 현재 요소의 인덱스이다. 초기값이 제공되지 않았다면 accumulator에 배열의 첫번째 값인 index 0의 값이 들어가고, currentIndex는 index 1부터 시작하게된다.
- array(optional): reduce()를 호출한 배열
초기값은 최초의 리듀서 호출에서 accumulator(누산기)에 제공하는 값이다. 초기값이 없다면 배열의 첫번째 요소(0번 인덱스)를 사용하고 초기값이 있다면 주어진 초기값을 사용한다.
reduce()의 반환값은 각 요소가 리듀서를 거쳐 누적된 값의 결과 값이다.
초기값이 없다면 발생하는 경우
- 배열의 첫번째 요소(0번 인덱스)를 accumulator에 누적한 후 1번 인덱스부터 reducer를 거친다.
- 배열의 요소 값이 1개인데 초기값도 제공하지 않은 경우 or 초기값은 있지만 배열이 빈 배열인 경우에는 그 단독 값을 리듀서를 거치지 않고 바로 반환한다.
- 배열이 비었는데 초기값도 없는 상태에서 reduce()를 호출하면
TypeError
오류가 발생한다.
이렇게 초기값을 주지 않으면 발생할 수 있는 경우의 수가 3가지이므로 초기값은 주는 것이 안전하다.
const sumCallback = ( acc, cur ) => { return acc + cur };
// 초기값 없이 reduce()실행할 경우 3가지
[1, 2, 3].reduce( sumCallback ); // 1 + 2 + 3 = 6 : 초기값이 없으므로 0번 인덱스를 accumulator에 누적
[1].reduce( sumCallback ); // 1 : 배열의 요소 값이 1개이고 초기값 X
[].reduce( sumCallback, 1 ); // 1 : 빈 배열에 초기값 1
[ ].reduce( sumCallback ); // TypeError
초기값이 있는 경우와 없는 경우의 비교
초기값이 없는 경우
[0, 1, 2, 3, 4].reduce(function(accumulator, currentValue, currentIndex, array) {
return accumulator + currentValue;
}); //최종 반환 값 10
callback | accumulator | currentValue | currentIndex | array | 반환 값 |
1번째 호출 | 0 | 1 | 1 | [0, 1, 2, 3, 4] | 1 |
2번째 호출 | 1 | 2 | 2 | [0, 1, 2, 3, 4] | 3 |
3번째 호출 | 3 | 3 | 3 | [0, 1, 2, 3, 4] | 6 |
4번째 호출 | 6 | 4 | 4 | [0, 1, 2, 3, 4] | 10 |
초기값이 없기 때문에, accumulator에 배열의 첫번째 값이 들어간 상태로 배열의 두번째 값 부터 리듀서를 거치기 시작한다. 따라서 콜백함수(리듀서) 호출은 4번만 실행된다.
초기값이 있는 경우 - 초기값 10
[0, 1, 2, 3, 4].reduce(function(accumulator, currentValue, currentIndex, array) {
return accumulator + currentValue;
}, 10); //최종 반환 값 20
callback | accumulator | currentValue | currentIndex | array | 반환 값 |
1번째 호출 | 10 | 0 | 0 | [0, 1, 2, 3, 4] | 10 |
2번째 호출 | 10 | 1 | 1 | [0, 1, 2, 3, 4] | 11 |
3번째 호출 | 11 | 2 | 2 | [0, 1, 2, 3, 4] | 13 |
4번째 호출 | 13 | 3 | 3 | [0, 1, 2, 3, 4] | 16 |
5번째 호출 | 16 | 4 | 4 | [0, 1, 2, 3, 4] | 20 |
초기값이 10으로 주어졌다. 따라서 accumulator에 10이 들어간 상태에서 주어진 배열의 첫번째 값인 0부터 리듀서를 거치기 시작한다. 콜백함수(리듀서)는 5번 실행된다.
reduce() 사용해보기
객체로 이루어진 배열에서의 값 합산
각 항목이 모두 리듀서를 거치게 하려면 반드시 초기값을 주어야 한다.
const initialValue = '';
const sum = [{x: 'Hello'}, {x: 'World'}, {x: '!'}].reduce(function (accumulator, currentValue) {
return accumulator + (currentValue.x + '*'); //요소 뒤에 별표 추가
}, initialValue)
console.log(sum) //Hello*World*!*
배열내의 요소수를 세어서 객체로 반환하기
const fruits = ['Apple', 'Banana', 'Banana', 'Lemon', 'Apple', 'Kiwi'];
const countedFruits = fruits.reduce(function (allFruits, fruit) {
if (fruit in allFruits) { //누산된 객체 allFruits에 해당 fruit의 property가 있으면
allFruits[fruit]++; //해당 fruit의 value값을 1 증가시킴
}
else {
allFruits[fruit] = 1; //allFruits에 해당 fruit의 property값이 없으면 만들어주고 1을 넣어줌
}
return allFruits;
}, {});
// countedFruits
// { Apple: 2, Banana: 2, Lemon: 1, Kiwi: 1 }
배열의 중복 항목 제거하기
let arr = [1, 2, 1, 2, 3, 5, 4, 5, 3, 4, 4, 4, 4];
let result = arr.sort().reduce((accumulator, current) => {
const length = accumulator.length
if (length === 0 || accumulator[length - 1] !== current) {
accumulator.push(current);
}
return accumulator;
}, []);
console.log(result); //[1,2,3,4,5]
'JavaScript' 카테고리의 다른 글
자바스크립트에서 불변성(Immutability)이란 (5) | 2021.03.16 |
---|---|
ECMAScript 와 JavaScript의 차이점 (0) | 2019.10.21 |
자바스크립트 문자열, single or double quotes?... and backtick (1) | 2019.10.02 |
[번역] 반복문안에서의 자바스크립트 async/await (4) | 2019.09.25 |
자바스크립트 reduce 안에서 async/await 쓰기 (0) | 2019.09.24 |