지금까진 아래와 같은 복잡한 자료구조를 학습해 보았습니다.
- 객체 – 키가 있는 컬렉션을 저장함
- 배열 – 순서가 있는 컬렉션을 저장함
하지만 현실 세계를 반영하기엔 이 두 자료구조 만으론 부족해서 맵(Map)과 셋(Set)이 등장하게 되었습니다.
맵
맵(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– 요소의 개수를 반환합니다.
예시:
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[key]는 Map을 쓰는 바른 방법이 아닙니다.map[key] = 2로 값을 설정하는 것 같이 map[key]를 사용할 수 있긴 합니다. 하지만 이 방법은 map을 일반 객체처럼 취급하게 됩니다. 따라서 여러 제약이 생기게 되죠.
map을 사용할 땐 map전용 메서드 set, get 등을 사용해야만 합니다.
맵은 키로 객체를 허용합니다.
예시:
let john = { name: "John" };
// 고객의 가게 방문 횟수를 세본다고 가정해 봅시다.
let visitsCountMap = new Map();
// john을 맵의 키로 사용하겠습니다.
visitsCountMap.set(john, 123);
alert( visitsCountMap.get(john) ); // 123
객체를 키로 사용할 수 있다는 점은 맵의 가장 중요한 기능 중 하나입니다. 객체에는 문자열 키를 사용할 수 있습니다. 하지만 객체 키는 사용할 수 없습니다.
객체형 키를 객체에 써봅시다.
let john = { name: "John" };
let visitsCountObj = {}; // 객체를 하나 만듭니다.
visitsCountObj[john] = 123; // 객체(john)를 키로 해서 객체에 값(123)을 저장해봅시다.
// 원하는 값(123)을 얻으려면 아래와 같이 키가 들어갈 자리에 `object Object`를 써줘야합니다.
alert( visitsCountObj["[object Object]"] ); // 123
visitsCountObj는 객체이기 때문에 모든 키를 문자형으로 변환시킵니다. 이 과정에서 john은 문자형으로 변환되어 "[object Object]"가 됩니다.
맵