JavaScript
의 모든 배열 객체의 부모인 Array.prototype
은 다양한 메서드를 가지고 있다.
이번에는 그중에서도 map(), filter(), reduce()
메서드에 대해서만 다뤄보려고 한다.
이 세 가지 메서드를 이용하면, 나머지 배열 메서드들을 대체할 수 있을 정도로 강력한 기능을 가지고 있으므로 꼭 알아두자!😆
map()
메서드는, 기존에 있던 배열에 있던 요소들을 콜백 함수를 이용해서 다른 형식의 배열로 바꿀 수 있는 메서드다.
map()
메서드의 구문은 다음과 같다.
arr.map(callback(element, index, arr) { return r });
element
는 배열의 요소, index
는 배열의 인덱스, arr
배열 객체를 가리키고 return
값이 존재한다.
일단 어떻게 동작하는지 코드를 통해 알아보도록 하자!😄
const arr = [1, 2, 3, 4, 5];
const result = arr.map(element => element * 2);
console.log(arr); // 1, 2, 3, 4, 5
console.log(result); // 2, 4, 6, 8, 10
위 코드는 arr
배열의 각 요소에 2를 곱한 배열을 반환하는 코드이다.
보고나서 'forEach()
메서드랑 다른게 뭐지?` 라고 생각할 수도 있지만, 두 메서드의 차이는 바로 반환값에 있다.
map()
메서드는 forEach()
메서드와 달리, 원본 배열을 손상하지도 않을뿐더러 새로운 배열을 만들어서 반환하고, 심지어 새 배열의 각 요소에 반환 값도 할당해줄 수 있다는 점이다!😮
이를 이용하면 아래처럼 배열의 구조 자체를 바꾸는 것도 가능하다.
const names = ['Michel', 'Tommy', 'Rachel' ,'Johnson'];
const weights = [60, 87, 53, 72];
const heights = [168, 182, 160, 175];
const person = names.map((n, i) => ({name : n, weight : weights[i], height : heights[i]}));
console.log(person);
/*
* [
* { name: 'Michel', weight: 60, height: 168 },
* { name: 'Tommy', weight: 87, height: 182 },
* { name: 'Rachel', weight: 53, height: 160 },
* { name: 'Johnson', weight: 72, height: 175 }
* ]
*/
배열의 각 요소들을 조합해서 객체 정보를 담고있는 배열의 형태로 변한것을 볼 수 있다.
이처럼 map()
메서드를 활용하면 원본 배열을 손상하지 않고, 배열을 원하는 형식으로 변경할 수 있다!
filter()
메서드는 이름에서도 알 수 있듯이, 조건을 충족하는 요소만을 남겨서 반환하는 메서드이다.
filter()
메서드의 구문은 map()
과 동일하므로 따로 외울 필요는 없다.
그렇다면 코드를 통해 사용 방법부터 보도록 하자!😉
const arr = [];
for(let i = 1; i <= 20; i++){
arr.push(i);
}
const even = arr.filter(num => num % 2 == 0);
console.log(even);
/*
* [
* 2, 4, 6, 8, 10,
* 12, 14, 16, 18, 20
* ]
*/
filter()
메서드를 이용해 1 ~ 20 까지의 정수를 담은 배열에서 짝수만을 뽑아낸 배열을 새로 만들어냈다.
이렇게 단순한 코드에서는 filter()
의 필요성을 느끼지 못 할 수도 있지만, filter()
메서드는 map()
메서드와 조합이 가능하다는 장점이 있다.😲
const person = [
{name : 'Joseph', age : 71},
{name : 'Kim', age : 13},
{name : 'Lee', age : 37},
{name : 'Jassy', age : 54},
{name : 'Mike', age : 46},
];
const result = person.filter(p => p.age >= 40).map(p => p.name);
console.log(result); // [ 'Joseph', 'Jassy', 'Mike' ]
위 코드는 나이가 40세 이상인 사람들의 이름만 모아서 배열로 만들어준다.
이처럼 filter()
와 map()
을 적절히 조합해서 사용하면, 원하는 배열을 간단하게 만들어 낼 수 있다!
이름에서 알 수 있듯이, reduce()
메서드는 배열의 요소들을 더해나감으로써 하나의 값으로 만들어주는 메서드다.
여기서 하나의 값은 정수가 될 수도 있지만, 객체 혹은 배열이 되는 경우도 있으므로 기억해두자!😳
reduce()
메서드의 구문은 map()
과 filter()
와 비슷하지만 다른 점이 하나 있다.
arr.reduce(callback(accumulator, element, index, arr) { return r }, initValue));
element
, index
, arr
,는 같은 역할을 하지만 accumulator
라는 매개 변수가 추가됐는데, 바로 이 accumulator
에 배열의 요소들을 더해서 하나의 값이 되도록 만들어 준다.
initValue
는 accumulator
의 초깃값을 명시해주는 매개 변수다.
설명만 보면 복잡해 보인다...😅 배열의 모든 수를 더하는 간단한 예제를 보면서 이해해보자!
const arr = [];
for(let i = 0; i <= 10; i++){
arr.push(i);
}
const sum = arr.reduce((acc, num) => acc += num, 0);
console.log(sum); // 55
reduce()
메서드를 이용해 배열에 저장되어있는 0부터 10까지의 정수를 모두 더해주는 코드이다.
이 정도의 예제는 굳이 reduce()
메서드를 사용할 필요가 없어보인다.. 라고 생각했다면 다음 예제를 보도록 하자!
const arr = "askmcosvausaowepksdnv".split('');
const alphabet = arr.reduce((obj, char) => {
obj[char] = ++obj[char] || 1;
return obj;
}, {});
console.log(alphabet);
/*
* {
* a: 3,
* s: 4,
* k: 2,
* m: 1,
* c: 1,
* o: 2,
* v: 2,
* u: 1,
* w: 1,
* e: 1,
* p: 1,
* d: 1,
* n: 1
* }
*/
size
26의 배열을 별도로 만들어 주지 않고도, 문자열에서 특정 알파벳이 몇 번이 나왔는지 저장한 객체를 반환해주는 코드다.
이처럼 reduce()
는 정수뿐만 아니라 객체 혹은 배열에도 값을 계속 누적해서 반환해줄 수 있는 강력한 기능을 가진 메서드다!
위에서 설명했던 세 개의 메서드 모두 좋은 기능을 가지고 있지만, 주의해야 할 점이 하나 있다!
바로 delete
키워드를 이용해 배열의 요소를 삭제했다면, 해당 요소에 대해서는 콜백 함수를 호출하지 않는다는 점이다.😢
하지만 보통 delete
키워드는 잘 사용하지도 않기도 하고, 그 외에 배열의 요소가 null
이거나 undefined
인 경우에도 정상적으로 동작하니 delete
키워드를 사용하지만 않는다면 문제될 일은 없다!
참고 자료
[Array.prototype.reduce() | MDN] https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
[Array.prototype.filter() | MDN] https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
[Array.prototype.map() | MDN] https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/map