목차
- 개요
- 문법
- 자세한 설명
- 예제
2. reduce 메서드
- 개요
- 문법
- 예제
3. map을 reduce로 바꿔보기
React를 배울 때 많이 쓰일 메서드인 map, reduce 메서드를 알아보자!
Array.prototype.map()
map() 메서드는 배열 내의 모든 요소 각각에 대하여 주어진 함수를 호출한 결과를 모아 새로운 배열을 반환한다.
- 배열 각각의 element들을 다 바꾸고 새로운 array를 가지고 싶을때
- map은 매개변수 안에 함수를 넣을 수 있도록 해줌
- 이 함수는 배열의 모든 item에 대해 실행됨
- 이 함수에서 무엇을 return하든간에 그 return한 값이 새로운 array에 들어가 있게 됨
- 즉, map은 하나의 배열에 있는 item을 내가 원하는 무엇이든지로 바꿔주는 역할을 하고, 그건 결국 새로운 배열로 return해줌
- 예전 배열을 가져와서 변형해주는 것
const array1 = [1, 4, 9, 16];
const map1 = array1.map(x => x * 2)
console.log(map1); // [2, 8, 18, 32]
array1이라는 배열이 있으면,
map 메서드를 통해 요소 각각 [1, 4, 9, 16]에 2배를 해주는 함수를 호출해서 새로운 배열 [2, 8, 18, 32]을 반환하게 한다.
문법
arr.map(callback(currentValue[, index[, array]])[, thisArg])
callback | 새로운 배열 요소를 생성하는 함수. 세 가지 인수(currentValue, index, array)를 가진다. |
currentValue | 처리할 현재 요소 |
index | 처리할 현재 요소의 인덱스 (선택사항) |
array | map()을 호출할 배열 (선택사항) |
thisArg | callback을 실행할 때 this로 사용되는 값 (선택사항) |
반환값 | 배열의 각 요소에 대해 실행한 callback의 결과를 모은 새로운 배열 |
자세한 설명
- map은 callback 함수를 각각의 요소에 대해 한번씩 순서대로 불러 그 함수의 반환값으로 새로운 배열을 만든다.
- callback 함수는 (undefined도 포함해서) 배열 값이 들어있는 인덱스에 대해서만 호출된다.
- 즉, 값이 삭제되거나 아직 값이 할당/정의되지 않은 인덱스에 대해서는 호출되지 않는다.
- callback 함수는 호출될 때 대상 요소의 값, 그 요소의 인덱스, 그리고 map을 호출한 원본 배열 3개의 인수를 전달받는다.
- thisArg 매개변수가 map에 전달된 경우 callback 함수의 this값으로 사용되고, 그 외의 경우 undefined값이 this 값으로 사용된다.
- callback 함수에서 최종적으로 볼 수 있는 this 값은 함수 내 this를 정하는 일반적인 규칙에 따라 결정된다.
- map이 처리할 요소의 범위는 첫 callback을 호출하기 전에 정해진다. map이 시작한 이후 배열에 추가되는 요소들은 callback을 호출하지 않는다.
- 배열에 존재하는 요소들의 값이 바뀐 경우 map이 방문하는 시점의 값이 callback에 전달된다. map이 시작되고, 방문하기 전에 삭제된 요소들은 방문하지 않는다.
- map을 호출한 배열의 중간이 비어있는 경우, 결과 배열 또한 동일한 인덱스를 빈 값으로 유지한다.
map 예제
map 예제 1 (배열에 들어있는 문자열을 대문자로 바꿔서 새로운 배열을 만들기)
['good', 'best'].map( (item) ⇒ item.toUpperCase( ) )
// (2) ['GOOD', 'BEST']
map 예제 2 (배열에 안에 있는 객체에서 키값을 추출해서 새로운 배열을 만들기)
const people =[
{
name: '짱구',
age: 6,
job: '유치원생',
},
{
name: '봉미선',
age: 30,
job: '가정주부',
},
{
name: '채성아',
age: 24,
job: '교사',
}
];
let jobs = people.map((item)=>{
return item.job
})
console.log(jobs); // (3) ['유치원생', '가정주부', '교사']
여기서 item은 각각 3개의 객체를 뜻한다. 각 객체의 job을 수집해서 새로운 배열을 만드는 것이다.
const people =[
{
name: '짱구',
age: 6,
job: '유치원생',
},
{
name: '봉미선',
age: 30,
job: '가정주부',
},
{
name: '채성아',
age: 24,
job: '교사',
}
];
let jobs = people.map((item)=>{
return `<li>${item.name}</li>`
})
console.log(jobs); // (3) ['<li>짱구</li>', '<li>봉미선</li>', '<li>채성아</li>']
각 객체의 name을 수집해서 새로운 배열을 만드는 것이다.
map 예제 3 (배열 속 객체를 재구성 하기 - 예제 설명을 위해 var 사용)
var kvArray = [{key:1, value:10},
{key:2, value:20},
{key:3, value: 30}];
var reformattedArray = kvArray.map(function(obj){
var rObj = {};
rObj[obj.key] = obj.value;
return rObj;
});
console.log(reformattedArray) // (3) [{1:10}, {2:20}, {3:30}]
- reformattedArray는 map을 통해 만들어질 새로운 배열을 뜻한다.
- callback 함수에 들어간 매개변수 obj는 배열 kvArray에서 각각의 객체 3개를 뜻한다.
- rObj[obj.key] = obj.value; 는 빈 객체인 rObj에다가 kvArray의 각각의 객체에서 빼낸 프로퍼티를 추가하는 것이다.
*참고) 대괄호 표기법으로 객체의 프로퍼티 추가하는 법
map 예제 4 (배열에 들어있는 숫자들의 제곱근을 구하여 새로운 배열을 만들기)
const numbers = [1, 4, 9];
const roots = numbers.map(Math.sqrt);
console.log(roots); // (3) [1, 2, 3]
// numbers는 그대로 [1, 4, 9]
Array.prototype.reduce()
reduce() 메서드는 배열의 각 요소에 대해 주어진 리듀서 (reducer) 함수를 실행하고, 하나의 결과값을 반환한다.
- reduce는 줄여서 작업한다
- 배열을 받아서 새로운 무언가(문자, 숫자, 배열, 객체)를 만들때 씀
- 초기값으로 무언가를 정한다.
- map (배열을 받아 새로운 배열을 반환)이 있어서 reduce에서는 배열을 잘 안씀
- {…spread}가 있어서 객체도 잘 안씀
문법
arr.reduce(callback(accumulator, currentValue, index, array), initialValue)
풀어서 설명하면 아래 코드와 같다.
const numbers = [1, 2, 3, 4];
numbers.reduce((누산값, 현재요소값, 현재요소의index, 현재배열) => {
return 다음누산값;
}, 초기누산값);
arr | 순회하고자하는 배열 |
callback | 배열의 각 요소에 대해 실행할 함수. 네가지 인수(accumulator, currentValue, currentIndex, array) |
accumulator | 누적 되는 값 - callback 함수의 반환값을 누적한다. - initialValue(초기값)을 설정한 경우 callback 최초 호출 시 initialValue로 초기화 - initialValue가 없는 경우 arr의 0번째 인덱스 값으로 초기화 |
currentValue | 처리할 현재 요소 |
currentIndex | 현재 배열 요소의 index (선택 사항) - initialValue를 제공한 경우 0, 아니면 1부터 시작한다. |
array | reduce()를 호출한 배열 (선택 사항) |
initialValue | callback의 최초 호출 시 accumulator 초기 값 (선택 사항) 빈 배열에서 초기값 없이 reduce()를 호출하면 오류가 발생한다. |
반환값 | 누적 계산의 결과 값 |
reduce 예제
reduce 예제 1 (기본 원리 쉽게 알아보기- 오브젝트 배열에서 원하는 항목의 값만 더하기)
const people =[
{
name: '짱구',
age: 6,
job: '유치원생',
},
{
name: '봉미선',
age: 30,
job: '가정주부',
},
{
name: '채성아',
age: 24,
job: '교사',
}
];
people.reduce((acc,cur)=>{
return acc+cur.age
}, 0)
// 60
< 코드 설명 >
- 초기값 0이 acc에 등록됨. acc=0
- 0이 밑에 줄의 acc로 들어감
- cur에는 6이 들어옴 (cur은 순환하는 무언가 )
- 0+6 (acc+cur) 하면 6됨
- 6이 acc로 올라감 (그냥 그렇게 생겨먹음. 누적값이라/한번돌면누적하고 또 한번돌면 누적하고)
- cur에 30이 들어옴
- 6+30 (acc+cur) 하면 36됨
- 36이 acc로 올라감
- cur에 24가 들어옴
- 36+24 (acc+cur) 하면 60됨 → 결국 최종값은 60
- 60를 반환하는게 reduce의 목적임
- reduce는 새로운 무언가를 “만들 때” 쓰니까 결과를 내뱉어줘야함 (return필요) (참고로 forEach는 내뱉지않음)
reduce 예제 2 (콘솔 출력으로 동작원리 자세히 알아보기)
const numbers = [1, 2, 3, 4];
const sum = numbers.reduce((acc, cur, i) => {
console.log(`${i}번째 콜백함수`)
console.log(`acc: ${acc}`);
console.log(`cur: ${cur}`);
return cur + acc;
}, 0);
console.log(`-----------`);
console.log(`sum: ${sum}`);
reduce 예제 3 (초기값이 있을 경우 값이 어떻게 전달되는 지 알아보기)
const arr = [1, 2, 3, 4];
function func(accumulator, currentValue, currentIndex, array) {
console.log("acc: " + accumulator + ", cur: " + currentValue
+ ", curIndex: " + currentIndex + ", array: " + array);
return accumulator + currentValue;
}
const initialValue = 0;
const sumWithInitial = arr.reduce(func, initialValue);
// 0 + 1 + 2 + 3 + 4
console.log(sumWithInitial);
reduce 예제 4 (초기값이 없을 경우 값이 어떻게 전달되는 지 알아보기)
const arr = [1, 2, 3, 4];
function func(accumulator, currentValue, currentIndex, array) {
console.log("acc: " + accumulator + ", cur: " + currentValue
+ ", curIndex: " + currentIndex + ", array: " + array);
return accumulator + currentValue;
}
const sumWithInitial = arr.reduce(func);
// 1 + 2 + 3 + 4
console.log(sumWithInitial);
reduce 예제 5 (배열 numbers를 입력으로 받아 각 요소를 2배로 만들어 새로운 배열을 반환하기)
function solution(numbers) {
return numbers.reduce((a, b) => [...a, b * 2], []);
}
< 코드 설명 >
ex. numbers = [1, 2, 3, 4, 5]
1. reduce 함수를 사용하여 배열 numbers를 반복하는데, 초기값으로 빈 배열 []을 사용한다.
2. 첫 번째 요소 1이 현재 요소 b로 전달된다. 현재의 누적값 a는 초기값인 빈 배열 []이다.
3. 현재 요소 b를 2배하여 1 * 2는 2가 된다. 이 값 2가 현재의 누적값 a에 추가되어 [2]가 된다.
4 .두 번째 요소 2가 현재 요소 b로 전달된다. 현재의 누적값 a는 [2]이다.
5. 현재 요소 b를 2배하여 2 * 2는 4가 된다. 이 값 4가 현재의 누적값 a에 추가되어 [2, 4]가 된다.
6. 세 번째 요소 3이 현재 요소 b로 전달된다. 현재의 누적값 a는 [2, 4]이다.
7. 현재 요소 b를 2배하여 3 * 2는 6이 된다. 이 값 6이 현재의 누적값 a에 추가되어 [2, 4, 6]이 된다.
8. 최종적으로는 [2, 4, 6]이 반환되어 각 요소가 2배가 된 새로운 배열이 만들어진다.
map을 reduce로 바꿔보기
map으로 만든 홀수 짝수 예제
const oneTwoThree = [1, 2, 3];
let result = oneTwoThree.map((v) => {
if (v % 2) {
return '홀수';
}
return '짝수';
});
result; // ['홀수', '짝수', '홀수']
< 코드 설명 >
배열 [1, 2, 3] 에서 1, 2, 3이 차례로 인수로 들어가게될 것이다.
- map 함수의 매개변수 v에 1이 들어온다.
- if 절을 만났는데 조건이 (v % 2) 이므로, (1 % 2) 즉, 1을 2를 나눴을때 나머지 값이 1이므로 true가 돼서 if절이 실행된다.
- return 값으로 '홀수'를 반환하고, 그것이 새로운 배열에 들어간다. // ['홀수']
- map 함수의 매개변수 v에 2이 들어온다.
- if 절을 만났는데 조건이 (v % 2) 이므로, (2 % 2) 즉, 2를 2를 나눴을때 나머지 값이 0이므로 false가 돼서 if절이 실행되지않고 다음 줄로 넘어간다.
- return 값으로 '짝수'를 반환하고, 그것이 새로운 배열에 추가된다. // ['홀수', '짝수']
- map 함수의 매개변수 v에 3이 들어온다.
- if 절을 만났는데 조건이 (v % 2) 이므로, (3 % 2) 즉, 3를 2를 나눴을때 나머지 값이 1이므로 true가 돼서 if절이 실행된다.
- return 값으로 '홀수'를 반환하고, 그것이 새로운 배열에 추가된다. // ['홀수', '짝수', '홀수']
위의 map예시를 reduce로 바꿔보자
const oneTwoThree = [1, 2, 3];
let result = oneTwoThree.reduce((acc, cur) => {
acc.push(cur % 2 ? '홀수' : '짝수');
return acc;
}, []);
result; // ['홀수', '짝수', '홀수']
< 코드 설명 >
- 초기값이 빈배열로 acc에 등록됨. acc=[ ]- [ ]이 매개변수인 acc로 들어감- cur에 1이 들어옴. ( cur % 2 ) 이므로, ( 1 % 2 ) 즉, 1을 2로 나눴을 떄 나머지 값이 1이므로 true가 돼서 '홀수'가 return된다. - acc.push('홀수') 이므로 빈배열[ ]인 acc에 '홀수'가 추가된다. // ['홀수']
- ['홀수']가 acc로 올라감 - cur에 2가 들어옴. ( cur % 2 ) 이므로, ( 2 % 2 ) 즉, 2을 2로 나눴을 떄 나머지 값이 0이므로 false가 돼서 '짝수'가 return된다. - acc.push('짝수') 이므로 ['홀수']인 acc에 '짝수'가 추가된다. // ['홀수', '짝수']
- ['홀수', '짝수']가 acc로 올라감 - cur에 3가 들어옴. ( cur % 2 ) 이므로, ( 3 % 2 ) 즉, 3을 2로 나눴을 떄 나머지 값이 1이므로 true가 돼서 '홀수'가 return된다. - acc.push('홀수') 이므로 ['홀수', '짝수']인 acc에 '홀수'가 추가된다. // ['홀수', '짝수', '홀수']
- 최종 결과 값(result)으로 ['홀수', '짝수', '홀수'] 가 나오게된다.
더 많은 다른 배열 메서드는 https://dev-ini.tistory.com/51 를 참고해주세요!
참고 자료
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/map
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
'Languages > JavaScript' 카테고리의 다른 글
[JavaScript] 나머지 매개변수(...), arguments 객체, 스프레드 문법 (2) | 2023.07.14 |
---|---|
[JavaScript] 구조분해할당 (destructuring assignment) (0) | 2023.07.09 |
[JavaScript] hasOwnProperty를 쓰는 이유 (0) | 2023.06.29 |
[JavaScript] 반복문 빠져나오기, 다음 반복으로 넘어가기, 중첩 반복문 한번에 빠져나오기 (break, continue, label) (2) | 2023.06.13 |
[JavaScript] 반복문 while, for, for in, for of , for each 총정리, 비교, 차이점 완전정복 (0) | 2023.06.12 |