자바스크립트 내장 메서드 중 제일 강력하고, 알아두면 다양한 곳에 활용할 수 있는 메소드가 map과 reduce다.
map 메서드는 다음과 같이 사용한다.
배열.map((요소, 인덱스, 배열) => { return 요소});
map의 기본원리는 간단하다. 반복문을 도려 배열 안의 요소들을 1대 1로 짝지어 주는 것이다. 매핑한다고도 표현한다. 어떻게 짝지어줄 것인가를 정의한 함수를 메서드의 인자로 넣어주면 된다.
const oneTwoThree = [1, 2, 3];
let result = oneTwoThree.map((v) => {
console.log(v);
return v;
});
// 콘솔에는 1, 2, 3이 찍힌다.
oneTwoThree; // [1, 2, 3]
result; // [1, 2, 3]
oneTwoThree === resultl // false
반복문으로 요소를 순회(1, 2, 3 순서로)하면서 각 요소를 어떻게 짝지어줄지 알려준다. 함수가 그냥 return v를 하기 때문에 같은 값을 그대로 짝짓는다. 알아둘 점은, map을 실행하는 배열과 결과롤 나오는 배열이 다른 배열이라는 것이다. 기존 배열을 수정하지 않고 새로운 배열을 만들어낸다 단, 배열 안에 객체가 들어있는 경우, 객체는 공유된다.
result = oneTwoThree.map((v) => {
return v + 1;
});
result; // [ 2, 3, 4]
result = oneTwoThree.map((v) => {
if (v % 2) {
return '홀수';
}
return '짝수';
});
result; // ['홀수', '짝수', '홀수']
규칙적인 배열만 반환할 수 있는게 아니라, 함수 안에 적어준대로 반환할 수 있기 때문에 자유도가 높다.
정리하자면, map은 배열을 1대1로 짝짓되 기존 객체를 수정하지 않는 매서드이다.
reduce 메서드는 다음과 같이 사용한다.
배열.reduce((누적값, 현잿값, 인덱스, 요소) => { return 결과}, 초깃값);
이전 값이 아니라 누적값이라는 것에 주의해야 한다. 누적값이기 때문에 다양하게 활용할 수 있다. reduce 메서드의 누적값을 설명하기 위해 덧셈 예시를 흔히 든다.
result = oneTwoThree.reduce((acc, cur, i) => {
console.log(acc, cur, i);
return acc + cur;
}, 0);
// 0 1 0
// 1 2 1
// 3 3 2
result; // 6
acc(누적값)이 초깃값인 0부터 시작해서 return하는대로 누적되는 것을 볼 수 있다. 초깃값을 적어주지 않으면 자동으로 초깃값이 0번째 인덱스의 값이 된다.
result = oneTwoThree.reduce((acc, cur, i) => {
console.log(acc, cur, i);
return acc + cur;
});
// 1 2 1
// 3 3 2
result; // 6
reduceRight는 reduce와 동작은 같지만 요소 순회를 오른쪽에서부터 왼쪽으로 한다는 점에서 차이가 있다.
result = oneTwoThree.reduceRight((acc, cur, i) => {
console.log(acc, cur, i);
return acc + cur;
}, 0);
// 0 3 2
// 3 2 1
// 5 1 0
result; // 6
위 예시에서 모두 덧샘을 사용했지만, reduce는 덧셈 곱셈만을 위한 것이 아니다. 초깃값을 활용해 어떤 일을 할 수 있는지 알아볼 수 있다.
map과 filter와 같은 함수형 메서드 모두 reduce로 모두 구현할 수 있다.
//result = oneTwoThree.map((v) => {
// if (v % 2) {
// return '홀수';
// }
// return '짝수';
//});
//result; // ['홀수', '짝수', '홀수']
result = oneTwoThree.reduce((acc, cur) => {
acc.push(cur % 2 ? '홀수' : '짝수');
return acc;
}, []);
result; // ['홀수', '짝수', '홀수']
초깃값을 배열로 만들고, 배열에 값들을 push하면 map과 같아진다. 이를 응용해 조건부로 push를 하면 filter와 같아진다.
// 홀수만 필터링하는 코드
result = oneTwoThree.reduce((acc, cur) => {
if (cur % 2) acc.push(cur);
return acc;
}, []);
result; // [1, 3]
이와 같이 sort, every, some, find, findIndex, includeseh 모두 reduce로 구현가능하다.
const promiseFactory = (time) => {
return new Promise((resolve, reject) => {
console.log(time);
setTimeout(resolve, time);
});
};
[1000, 2000, 3000, 4000].reduce((acc, cur) => {
return acc.then(() => promiseFactory(cur));
}, Promise.resolve());
// 바로 1000
// 1초 후 2000
// 2초 후 3000
// 3초 후 4000
초깃값을 Promise.resolve()로 한 후에, return된 프로미스에 then을 붙여 다음 누적값으로 넘기면 된다. 프로미스가 순차적으로 실행됨을 보장할 수 있다.
반복되는 모든 것에는 reduce를 쓸 수 있다.
map과 reduce 외에도 배열의 메서드인 sort, filter, every, some, find, findIndex, includes 정도 알아두면 배우 유용하다.