[TIL] JS(ES6) Map을 펼쳐보자

SammyJung·2021년 6월 21일
0
post-thumbnail

들어가면서

오늘은 자바스크립트 ES6에서 추가된 데이터 타입의 종류 맵과 셋에 대해서 정리해보려 합니다.
아래 내용에서 <정재남> 님이 쓰신 <코어자바스크립트> 책을 참고하여 블로그 글을 작성했습니다.
참고 부탁드립니다.

자바스크립트의 데이터 타입은 크게 기본형과 참조형이 있습니다. 기본형에는 숫자, 문자열, boolean, null, undefined 등이 있고 ES6에서 심볼(symbol)이 추가 되었습니다.

참조형은 객체, 배열, 날짜(date), 정규표현식(RegExp) 등과 오늘 다뤄볼 Map과 WeakMap, set과 WeakSet 이 있습니다.

기본형과 참조형의 차이점

기본형은 값이 담긴 주솟값을 바로 복제하는 반면 참조형은 값이 담긴 주솟값들로 이루어진 묶음을 가리키는 주솟값을 복제한다는 점이 다르다.

Map

  • 맵은 키가 있는 데이터를 저장한다는 점에서 객체와 비슷하다. 값들을 매핑하기 위한 새로운 데이터 구조이다. Map객체는 간단한 키와 값을 서로 연결(매핑)시켜 저장하며 저장된 순서대로 각 요소들을 반복적으로 접근할 수 있도록 합니다.

Map과 일반객체와의 차이점

1) 키에 제약이 없다

  • 맵은 객체와 달리 키를 문자형으로 변환하지 않고 키에 자료형에 대한 제약이 없습니다. 문자열 뿐만 아니라 숫자,배열,객체 어떤 것이 와도 상관이 없다!

오! 맵은 객체도 키로 허용한다고?? => YES

객체도 키로 쓸 수 있습니다. 이게 바로 맵의 가장 중요한 기능 중 하나!

만약에 객체형 키를 일반객체에 써본다면

let sam = {name: "sammy"};

//객체를 하나 만듭니다.
let visitsCountObj = {};

// 객체(john)를 키로 해서 객체에 값(123)을 저장해봅시다.
visitsCountObj[sam] = 1101;

원하는 값(1101)을 얻으려면? 어떻게 해야할까요??

아래와 같이 키가 들어갈 자리에 object Object를 써줘야합니다.
visitsCountObj는 객체이기 때문에 모든 키를 문자형으로 변환시키게 되고, 이 과정에서 john은 문자형으로 변환되어 "[object Object]"가 됩니다.

alert( visitsCountObj["[object Object]"] ); // 1101

2) 맵은 삽입 순서를 기억합니다.

  • 객체가 프로퍼티 순서를 기억하지 못하는 것과 달리 맵은 값이 삽입된 순서대로 순회를 실시합니다.

cf) 맵이 키를 비교하는 방식

맵은 SameValueZero라 불리는 알고리즘을 사용해 값의 등가 여부를 확인합니다. 이 알고리즘은 일치 연산자 ===와 거의 유사하지만, NaN과 NaN을 같다고 취급하는 것에서 일치 연산자와 차이가 있습니다. 따라서 맵에선 NaN도 키로 쓸 수 있습니다.

cf) Nan === Nan 은 true? false?
false 가 나옵니다! 근데 map 에서는

이 알고리즘은 수정하거나 커스터마이징 하는 것은 안된다고 합니다!

*SameValueZero는 다음에 더 자세히 다뤄보기로 하겠습니다.
MDN에서 설명하는 SameValueZero

Map의 주요 메서드와 프로퍼티

  • new Map() – 맵을 만듭니다.
  • map.set(key, value) – key를 이용해 value를 저장합니다.
  • map.get(key) – key에 해당하는 값을 반환합니다. key가 존재하지 않으면 undefined를 반환합니다.
  • map.has(key) – key가 존재하면 true, 존재하지 않으면 false를 반환합니다.
  • map.delete(key) – key에 해당하는 값을 삭제합니다.
  • map.clear() – 맵 안의 모든 요소를 제거합니다.
  • map.size – 요소의 개수를 반환합니다.

ex)

let map = new Map();

map.set('1', 'str1');   // 문자형 키
map.set(1, 'num1');     // 숫자형 키
map.set(true, 'bool1'); // 불린형 키

// 객체는 키를 문자형으로 변환한다는 걸 기억하고 계신가요?
// 맵은 키의 타입을 변환시키지 않고 그대로 유지합니다. 따라서 아래의 코드는 출력되는 값이 다릅니다.
alert( map.get(1)   ); // 'num1'
alert( map.get('1') ); // 'str1'

alert( map.size ); // 3

Map을 바르게 쓰는 방법

map[key] = 2로 값을 설정하는 것 같이 map[key]를 사용할 수 있긴 하지만 이 방법은 map을 일반 객체처럼 취급하게 됩니다. 사용 엑스엑스!

map을 사용할 땐 map전용 메서드 set, get 등을 사용해야만 합니다.

체이닝

map.set을 호출할 때마다 맵 자신이 반환됩니다. 이를 이용하면 map.set을 '체이닝(chaining)'할 수 있습니다.

map.set('1', 'str1')
  .set(1, 'num1')
  .set(true, 'bool1');

맵의 요소에 반복작업하기

  • map.keys() – 각 요소의 키를 모은 반복 가능한(iterable, 이터러블) 객체를 반환합니다.
  • map.values() – 각 요소의 값을 모은 이터러블 객체를 반환합니다.
  • map.entries() – 요소의 [키, 값]을 한 쌍으로 하는 이터러블 객체를 반환합니다.
    이 이터러블 객체는 for..of반복문의 기초로 쓰입니다.

객체를 Map으로 바꾸기

  • 각 요소가 키-값 쌍인 배열이나 이터러블 객체를 초기화 용도로 맵에 전달해 새로운 맵을 만들 수 있습니다.
// 각 요소가 [키, 값] 쌍인 배열
let map = new Map([
  ['1',  'str1'],
  [1,    'num1'],
  [true, 'bool1']
]);

alert( map.get('1') ); // str1

//ex2
let obj = {
  name: "John",
  age: 30
};

let map = new Map(Object.entries(obj));

alert( map.get('name') ); // John

평범한 객체를 가지고 맵을 만들고 싶다면 내장 메서드 Object.entries(obj)를 활용해야 합니다. 이 메서드는 객체의 키-값 쌍을 요소([key, value])로 가지는 배열을 반환합니다.

Map을 객체로 바꾸기

Object.fromEntries를 사용하면 가능합니다. 이 메서드는 각 요소가 [키, 값] 쌍인 배열을 객체로 바꿔줍니다.

let prices = Object.fromEntries([
  ['banana', 1],
  ['orange', 2],
  ['meat', 4]
]);

// now prices = { banana: 1, orange: 2, meat: 4 }

alert(prices.orange); // 2

map.entries()를 호출하면 맵의 [키, 값]을 요소로 가지는 이터러블을 반환합니다. Object.fromEntries를 사용하기 위해 딱 맞는 형태이죠.

let obj = Object.fromEntries(map); // .entries()를 생략가능
profile
안녕하세요! 프론트엔드 개발자 새미입니다:D

0개의 댓글