hoon's bLog

Javascript 자바스크립트 코딩의 기술 3장 특수한 컬렉션을 이용해 코드 명료성을 극대화하라 (2) 본문

IT/Javascript

Javascript 자바스크립트 코딩의 기술 3장 특수한 컬렉션을 이용해 코드 명료성을 극대화하라 (2)

개발한기발자 2024. 1. 10. 17:27
반응형


3장 특수한 컬렉션을 이용해 코드 명료성을 극대화하라

tip14. 맵과 펼침 연산자로 키-값 데이터를 순회하라

객체는 순회하기가 번거롭다. 그나마 for ...in문을 사용할 수 있지만 키 외에는 접근할 수 없다.

const filters = {
    color: 'black',
    breed: 'Retriever'
};

function getAppliedFilters(filters) {
    const keys = Object.keys(filters);
    const applied = [];
    for (const key of keys) {
        applied.push(`${key}:${filters[key]}`);
    }
    return `선택한 조건은 ${applied.join(',')} 입니다.`;
}
  • Object.keys()로 객체의 키를 배열로 옮기고, for문으로 키를 순회하면서, 객체를 참조해 값을 꺼낸다.
  • 또한, 객체의 순서를 보장되지 않으므로 정렬을 할 수 없다. 필터링 조건을 정렬하려면 키를 정렬해야 한다.
const filters = new Map()
    .set('color', 'black')
    .set('breed', 'Retriever')

filters.entries();
// MapIterator { ['color', 'black'], ['breed', 'Retriever']}

function getAppliedMapFilters(filters) {
    const applied = [];
    
    for (const [key, value] of keys) {
        applied.push(`${key}:${value}`);
    }
    
    return `선택한 조건은 ${applied.join(',')} 입니다.`;
}

console.log(...filters);
// ['color', 'black'], ['breed', 'Retriever']
  • ES2017부터 공식적으로 명세에 Object의 내장 메소드 Object.entries()로 추가되었다고 한다!
    Map에서도 스프레드 연산자를 사용할 수 있다.
  • 배열은 단일 값만 반환되지만 Map은 키-값 쌍이 반환된다.
  • 반면에 Map은 정렬과 순회에 필요한 기능이 내장되어 있다. 아래 코드를 통해 알아보자!!
const filters = new Map().set('색상','검정색').set('견종','래브라도리트리버')

function checkFilters(filters) {
  for (const entry of filters) {
    console.log(entry);
  }
}

checkFilters(filters)
//["색상", "검정색"]
//["견종", "래브라도리트리버"]

filters.entries();
// MapIterator {"색상" => "검정색", "견종" => "래브라도리트리버"}
  • entries()는 키-값 쌍으로 묶은 Map Iterator를 반환한다.
  • Map은 직접 순회 가능하므로 키를 먼저 꺼낼 필요 없고, 해체 할당 문법으로 즉시 변수로 할당 할 수 있다.
function getAppliedFilters(filters) {
  const applied = [];
  for ( const [key, value] of filters ) {
    applied.push(`${key}:${value}`);
  }
  return `선택한 조건은 ${applied.join(', ')} 입니다.`;
}

getAppliedFilters(filters);
  • Map이 순서를 저장해 항상 맵의 첫 번째 항목을 첫 번째로 받지만, 배열 메서드처럼 sort() 메서드가 없다. 따라서 정렬을 위해 아래와 같이 코드를 수정해준다.
function sortByKey(a, b) {
  return a[0] > b[0] ? 1 : -1;
}

function getSortedAppliedFilters(filters) {
  const applied = [];
  for (const [key, value] of [...filters].sort(sortByKey)) {
    applied.push(`${key}:${value}`);
  }
  return `선택한 조건은 ${applied.join(', ')} 입니다.`;
}

getSortedAppliedFilters(filters);
// "선택한 조건은 견종:래브라도리트리버, 색상:검정색 입니다."
  • 위 코드에 문제점은 Map으로 시작했지만 실제 for문이 실제로 순회하는 것은 맵이 아닌 새로운 배열이다.
  • Map을 배열로 변환해 함수를 단순하게 만들었고, 배열로 변환함으로써 배열 메서드도 사용이 가능하다.
  • 앞에서 맵 객체를 이용한 함수 대신 배열 메서드를 체이닝을 사용해 작성하면 다음과 같다.
function getAppliedFilters(filters) {
  const applied = [...filters]
    .sort(sortByKey)
    .map(([key, value]) => {
      return `${key}:${value}`;
    })
    .join(', ');
  return `선택한 조건은 ${applied} 입니다.`;
}
// "선택한 조건은 견종:래브라도리트리버, 색상:검정색 입니다."

tip15. Map  생성 시 부수 효과를 피하라

  • 맵의 인스턴스를 이용해 작업하면 몇가지 문제점이 있다.
  • 맵의 복사본은 어떻게 생성할까? 부수 효과를 피하면서 맵을 변경하려면 어떻게 해야 할까?
  • 우선 복사, 조작 문제를 혼합한 예제를 살펴보자.
  • 앞에 살펴봤던 반려견 입양 사이트 예제 코드에서 사용자가 필터링 조건을 선택했는데, 아마 필터링의 기본값도 필요할 것이다.
  • 즉, 사용자가 명시적으로 설정하지 않는 조건에 대해서는 기본값을 적용, 추가로 사용자가 적용하는 필터링 조건은 기본값을 덮어 쓴다.
const defaults = new Map()
  .set('색상','갈색')
  .set('견종','비글')
  .set('지역','캔자스')

const filters = new Map()
  .set('색상', '검정색')
  • 위와 같이 기본값과 추가 필터링 조건을 합칠려면 어떻게 해야될까?
  • 부수 효과를 신경쓰지 않으면 has메서드를 사용해 키를 체크해 설정한다.
function applyDefaults(map, defaults) {
  for (const [key,value] of defaults) {
    if (!map.has(key)) {
      map.set(key, value); // 여기서 filters를 조작한다.
    }
  }
}

console.log(filters);
// Map(3) {"색상" => "검정색", "견종" => "비글", "지역" => "캔자스"}
  • 기본값, 사용자 데이터를 병합하는 것이 목적이라면 성공!
  • 필터링 조건 객체에 대한 사용을 위해서, 데이터에 필터링 조건 적용, 사용자가 선택한 조건을 알려주는 부분을 고려해야 한다.
  • 위 코드와 같은 경우에는 사용자가 선택한 조건에 기본값도 모두 노출 된다.
  • 해결 방법은 entries, 펼침연산자를 사용하여 사본을 만드는 것이다. 아래 코드로 살펴보자.
function applyDefaults(map, defaults) {
    const copy = new Map([...map]);
    for (const [key,value] of defaults) {
        if (!copy.has(key)) {
            copy.set(key, value); // 여기서 filters를 조작한다.
        }
    }
    return copy;
}
  • 여러가지 키의 존재 여부를 일일이 확인하고 있다.
  • Map은 객체와 마찬가지로 하나의 키를 한 번만 사용할 수 있다.
  • 따라서, 새로운 키로 맵을 생성하면 어떤 값이든 해당 키에 마지막으로 선언한 값을 사용한다. 즉, 값을 설정하는 대신 갱신한다.
const filters = new Map().set('color', 'black').set('color', 'brown')

filters.get('color'); // 'brown'
  • 그리고 위의 applyDefaults 함수를 개선 하면 아래와 같다!
function applyDefaults(map, defaults) {
    return new Map([...defaults, ...map]);
}

Reference

자바스크립트 코딩의 기술 요약 / 정리

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Set/entries

 

Set.prototype.entries() - JavaScript | MDN

entries() 메소드는 Set 객체의 각각의 요소를 삽입순서대로 [값, 값]의 형태로 가진 배열의 새로운 Iterator 객체를 반환합니다. Set객체에는 Map객체의 key가 없습니다. 그러나, Map 객체의 API와 비슷하

developer.mozilla.org

 

728x90
반응형