map으로 해결 및 map의 잘못된 사용

김민재·2023년 1월 31일
0
  • 함수형 프로그래밍은 가능한 한 가지 의미있는 작업을 하는 순수 함수를 만들고 이 함수들을 조합해서 더 큰 프로그램을 만든다.

  • 함수의 재사용성과 합성을 용이하기 위해 함수는 여러가지 일이 아닌 하나의 일만 제대로 처리하는 것이 중요

페이지 기능 단위 쪼개기

  1. 아이템 목록 화면 그리기
  • 재고 있는 경우
  • 없는 경우
  1. 전체 수량 표시
  2. 전체 가격 표시
  • 상품을 상태별로 그려주는 함수인 stockItem, outOfStockItem으로 나누고
    아이템의 재고 상태를 판단해 어떻게 그려줄 건지 판단하는 item 함수로 분리되어 각각 상태 테스트 하기 용이
  • 함수 순수하게 만들고 적절한 크기로 나누기
const stockItem = (item: Item) :string=> {
  const name =	item.name;
  const price = item.price;
  const quantity = item.quantity;
  return `이름: ${name}, 가격 : ${price}, 수량 ${quantity}` 
}

const outOfStockItem = (item: Item): string => {
   const name =	item.name;
  const price = item.price;
  const quantity = item.quantity;
  return `이름: ${name} 품절, 가격 : ${price}, 수량 ${quantity}` 
}

const item = (item: Item): string => {
  if (item.outOfStock) {
    return outOfStockItem(item)
  } else {
    return stockItem(item)
  }
}


const totalCnt = (): string => {
  let totalCnt = 0;
  for (let i = 0; i < cart.length; i++) {
    if (!cart[i].outOfStock) {
      totalCnt += cart[i].quantity;
    }
  }
  return `전체수량: ${totalCnt}`
}


const totalPrice = (): string => {
  let totalPrice = 0;
  for (let i = 0; i < cart.length; i++) {
    if (!cart[i].outOfStock) {
    totalPrice += cart[i].price * cart[i].quantity;
    }
  }
  return `전체수량: ${totalCnt}`
}
  • 그러나 여기까지 만든 item, totalCnt, totalPrice는 순수함수로 보기 어려운데 일종의 전역변수인 cart를 묵시적으로 의존하며 아무런 인자를 받고 있지 않기 때문

  • 각각의 함수에 list인자 받도록 수정 필요, 내부에 for문과 if문 중복되는 부분은 고차함수로 추상화하기


const totalCal = (list: Array<Item>, getValue: (item: Item) => number) => {
  // 전체 목록 중 재고가 있는 상품만 getValue를 실행하고 그 값을 모두 더함

  list
  // 1, 재고가 있는 상품만 분류 - filter
  .filter(item => item.outOfStock ===false)
  // 2. 분류된 상품에 대해 getValue 실행 - map
  .map(getValue)
  // 3. getValue가 실행된 값 모두 더하기 - reduce
  .reduce((total,value)=> total +value, 0) 
  
  // let total = 0
  // for (let i = 0; i < list.length; i++) {
  //   if (!list[i].outOfStock) {
  //     total += getValue(list[i]);
  //   }
  // }
  // return total
}

const totalCnt = (list:Array<Item>): string => {
  let totalCnt = totalCal(list, (item)=>item.quantity);
  return `전체수량: ${totalCnt}`
}


const totalPrice = (list:Array<Item>):string => {
  let totalPrice =  totalCal(list, (item)=>item.price);
  return `전체수량: ${totalCnt}`
}

const list = (list: Array<Item>) => { 
// 목록에 있는 아이템 태그 변경
  return `
  ${list
  // 태그 목록을 하나 문자열로 연결
    .map(item)
  .reduce((tags,tag)=>tags+tag,"")
}`
}
  • 배열의 메소드 체이닝으로 해결했으나 람다 JS라이브러리를 함수와 함수 합성으로 해결 가능

map 잘못 사용하는 경우

  • map 함수 내부에 함수 타입을 익명함수를 쓴 경우, 함수가 값을 반환하라는 오류가 나옴
    - 배열에 메소드 필터, 맵, 폴드 등의 메서드 존재, 콜백함 수내 리턴 문 없으면 실수
    • 만약 리턴문 없다면 대신 ForEach를 쓰라 권장
    • 그러나 forEach는 타입 파라미터를 사용하지 않고 void를 리턴하여 함수 합성이 불가
    • 입력값에 대응되는 의미있는 값을 만들지 못하고 있는 예, 따라서 map이 의미가 없다(부수효과만 있기에)
const totalCal2 = (list: Array<Item>, getValue: (item: Item) => number) => {
  // 재고가 있는 상품만 getValue를 실행하기 위해 새로운 변수 result추가
  const result:Array<number> = []
  list.forEach(function (item) {
    if (!item.outOfStock) {
    result.push(getValue(item))
    }
  })
    
  return result.reduce((total,value)=> total + value)
}

이중 for문

const suits = ["♠", "♥", "♣", "♦"];
const numbers = [
  "2",
  "3",
  "4",
  "5",
  "6",
  "7",
  "8",
  "9",
  "10",
  "J",
  "Q",
  "K",
  "A"
];



const cards: Array<string> = []
// 중첩된 for 구무
for (const suit of suits) {
  for (const number of numbers) {
    cards.push(suit+number)
  }
}
// 우리가 원하는 작업 정리

// 모든 카드 목록 아래의 작업이 완료
const card2=
// 아래의 작업을 모든 무늬에 적용
  suits.flatMap((suit)=> // 문자열 배열에 리턴된 함수를 다시 map에 적용해 배열이 중첩된 문자열 리턴
  // 아래의 작업을 모든 숫자에 적용
  numbers.map((number)=> // 최종적 리턴은 문자열의 배열
    // 한장의 카드는 무늬외 숫자를 연결한 문자열
    suit + number))
    // 무늬별로 나누어진 카드를 하나로 합침
// .flat()
cards
card2
profile
자기 신뢰의 힘을 믿고 실천하는 개발자가 되고자합니다.

0개의 댓글