ES6) map, filter, reduce 메서드 사용법

onezerokang·2021년 11월 24일
1

Javascript

목록 보기
4/7
post-thumbnail

필자는 평소 코딩을 하면서 loop을 사용할 때 forEach를 많이 사용했다. forEach가 for loop이나 for...of 문보다는 깔끔하지만 복잡한 작업을 하다보면 코드가 난잡해지곤 했다. 그래서 오늘은 map, filter, reduce 메서드란 무엇이고, 어떻게 사용하는지, 그리고 기존 코드를 어떻게 리팩터링 했는지를 작성해보았다.

map

map 메서드는 배열의 모든 요소에 콜백함수를 적용시켜 새로운 배열을 만들고 싶을 때 사용하는 메서드다.

arr.map(callback(currentValue[, index[, array]])[, thisArg])

callback: 배열의 모든 요소에 적용되어 새로운 배열 요소를 생성하는 함수. 다음 세 가지 인수를 갖는다.
currentValue: callback이 적용될 현재 요소
index: 처리할 현재 요소의 index
array: map을 호출한 배열
thisArg: callback을 실행할 때 this로 사용되는 값

위 문법을 보면 callback에서 세 가지 인수를 갖지만 아직까지는 currentValue와 index외의 값을 사용하는 것을 본적이 없다.

사용예시 1

const numbers = [1, 2, 3, 4];
const updatedNumbers = numbers.map((number) => {
  return number * 2;
})
console.log(updatedNumbers);
//[2, 4, 6, 8]

사용예시 2

const fruits = [
  {name: "Apple", price: 1000},
  {name: "Banana", price: 5000},
  {name: "Grape", price: 4000},
  {name: "Watermelon", price: 20000},
]

const fruitsNames = fruits.map((fruit) => {
  return fruit.name;
})
console.log(fruitsNames);
//["Apple", "Banana", "Grape", "Watermelon"]

filter

filter 메서드는 Boolean만 반환할 수 있는데 true일 경우 해당 요소를 새로운 배열에 추가하고, false일경우 추가하지않는다. filter 메서드는 특정 조건에 일치하는 요소만 배열에 담고 싶을 때 사용한다. 사용 문법과 예시는 다음과 같다.

arr.filter(callback(element[, index[, array]])[, thisArg])

사용예시1

const fruits = [
  {name: "Apple", price: 1000},
  {name: "Banana", price: 5000},
  {name: "Grape", price: 4000},
  {name: "Watermelon", price: 20000},
]

const chipFruits = fruits.filter((fruit) => {
  return fruit.price < 5000;
})
console.log(chipFruits);
//[{name: "Apple", price: 1000}, {name: "Grape", price: 4000}]

reduce

개인적으로 가장 배우기 어려웠던 메서드가 reduce다. 하지만 여러 예제를 접하다보면 생각보다 어렵지 않다는 것을 알 수 있었다. reduce는 reducer라는 함수를 통해 하나의 데이터를 반환하는 함수다. 반환된 데이터가 String, Number, null, undefined, Array, Object 등 무엇이든 될 수 있다.

문법

arr.reduce(callback[, initialValue])

reduce의 callback의 핵심은 accumulatorcurrentValue를 갖는다는 점이다. accumulator, 한국어로는 누산기는 콜백의 반환값을 누적한다. 만약 누적값이 없다면 initialValue가 됩니다.

만약 initalValue를 설정하지 않았다면 첫번째 accumulator 는 배열의 0번째 index가 되고 currentValue는 1번째 index가 됩니다. initialValue를 설정했다면 첫번째 accumulator는 initalValue가 되고 currentValue는 0번째 index가 됩니다.

사용예시1

const fruits = [
  {name: "Apple", price: 1000},
  {name: "Banana", price: 5000},
  {name: "Grape", price: 4000},
  {name: "Watermelon", price: 20000},
]
const totalPrice = fruits.reduce((acc, cur) => {
  return acc + cur.price;
}, 0)
console.log(totalPrice)
//30000

실제 리팩터링했던 코드

상황1: 커머스 서비스에서 결제 시 총 가격을 더해서 결제 모듈에 전달해야 하는 상황

기존코드

const products = await Product.find({_id: req.params.id});  

let totalPrice = 0;
products.forEach((product) => {
  totalPrice += product.price;
})
res.status(200).json({totalPrice});

리팩터링한 코드

const products = await Product.find({_id: req.params.id});

const totalPrice = products.reduce((acc, cur) => {
  return acc + cur;
}, 0)
res.status(200).json({totalPrice});

console.log(groupedProducts);
// {
//   a: [
//     {seller: "a", product: "양말", quantity: 3},
//     {seller: "a", product: "목도리", quantity: 1},
//   ],
//   b: [{seller: "b", product: "바나나 우유", quantity: 24}]
// }

상황2: 장바구니에서 같은 판매자끼리 분류해야 하는 상황(코드는 단순화, 변형 시켰습니다)
기존코드

const products = [
  {seller: "a", product: "양말", quantity: 3},
  {seller: "a", product: "목도리", quantity: 1}, 
  {seller: "b", product: "바나나 우유", quantity: 24}, 
]

const groupedProducts = {};
products.forEach((product) => {
  if(!groupedProducts[product.seller]) {
    groupedProducts[product.seller] = [];
  }
  groupedProducts[product.seller].push(product);
});

리팩터링한 코드

const products = [
  {seller: "a", product: "양말", quantity: 3},
  {seller: "a", product: "목도리", quantity: 1}, 
  {seller: "b", product: "바나나 우유", quantity: 24}, 
]

const groupedProducts = products.reduce((acc, curr) => {
  var key = curr['seller'];
  //acc가 curr['seller']를 key로 가지고 있지 않는다면
  //해당 키를 가지고 있는 배열을 만들고, 그 배열에 curr를 push 한다.
  if(!acc[key]) {
    acc[key] = [];
  }
  acc[key].push(curr);
  return acc;
}, {})

console.log(groupedProducts);
// {
//   a: [
//     {seller: "a", product: "양말", quantity: 3},
//     {seller: "a", product: "목도리", quantity: 1},
//   ],
//   b: [{seller: "b", product: "바나나 우유", quantity: 24}]
// }

요약

map: 배열의 요소들을 각각 변환한다. 변경된 항목이 포함된 정확히 동일한 길이의 새 배열을 반환한다.

filter: 배열의 특정 요소를 제거한 새 배열을 반환한다.

reduce: 각 요소를 처리하여 한의 값을 반환한다.

소감

이번에 map, filter, reduce를 공부하면서 느낀점은 배열을 순회하는 메서들은 서로 대체가 가능하다는 점이다. 예를들면 map, filter, reduce를 쓰지 않고 forEach로 전부처리가 가능하던지, forEach, map, filter를 쓰지 않아도 reduce로 처리가 가능하다. 하지만 그 메서드가 가장 적합한 작업은 그 메서드로 처리하는게 가장 좋다. 그것이 코드도 깔끔해지고 읽는 사람도 의도를 파악하기 쉽기 때문이다.

출처

https://www.youtube.com/watch?v=vqdzVZxoRtM
https://brunch.co.kr/@swimjiy/15
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/filter
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce

profile
블로그 이전 했습니다: https://techpedia.tistory.com

0개의 댓글