Map
자바스크립트에는 객체와 배열이라는 강력하고 유용한 자료구조를 제공한다. 하지만 이 두가지 자료구조만으로는 부족하기 때문에 ES6에서 Map, Set 자료구조가 등장하게 되었다.
Map은 흔히 알고 있듯이 키와 값 쌍으로 이루어진 자료 구조이다. 이 점만 보면, 자바스크립트의 객체와 크게 다를 것이 없어보이는데 왜 Map이 등장하였을까?
바로 객체의 key는 항상 스트링 형태로 저장되는 것에 비해 Map 자료 구조의 key는 다양한 자료형을 허용한다는 점에서 차이가 존재한다. 이외에도 자바스크립트에서 Map은 어떠한 특징을 가지고 있고 어떠한 메소드를 통해 사용하는지 알아보자.
Map vs 객체
Map 과 객체의 큰 차이점은 key의 자료형의 허용 범위라고 하였는데 이외에는 어떠한 차이점이 있을까? 사실상 객체와 Map은 성능상의 큰 차이점은 없지만, 가지고 있는 특징이 조금 다르기 때문에 상황에 따른 성능의 차이는 존재한다.
객체의 경우에는, 다음과 같은 상황에서 유용하다.
- 데이터를 json으로 변환하여 작업하는 경우 (Map은 json으로 변환X)
- 간단한 데이터 구조를 선택해야 하는 경우
Map의 경우는 다음과 같은 상황에서 유용하다
- 방대한 데이터를 다뤄야 하는 경우( Map은 get, set, has와 같은 함수로 데이터에 쉽게 접근 가능 )
- 반복 또는 요소 순서가 매우 중요한 경우
Map은 객체와는 달리 키의 순서를 유지하고 iteration을 염두에 두고 구축되었기 때문에 반복 또는 요소의 순서가 중요한 경우에 객체보다 안정적인 성능을 보장한다.
Map 객체 생성
자바스크립트에서 Map은 객체를 생성하기 위한 리터럴 방식은 지원하지 않고 new Map() 생성자를 통해서만 객체를 생성할 수 있다. 이 때 생성자의 인수로 2차원 배열에 key와 value 를 넘겨준다.
// Map 객체 생성
// new Map
// 초기값 => 2차원 배열
// 빈 Map 객체
const map1 = new Map();
// 초기값 설정
const map2 = new Map([
['first', 1],
['second', 2]
])
// 다양한 자료형 가능
const map3 = new Map([
[1, 'map'], // 숫자형 키
[true, 2], // 불린형 키
['str', true], // 문자형 키
[true, 4], // 중복되면??
])
// 뒤의 값으로 덮어씌워짐
// key는 unique함을 보장
console.log(map3) // Map(3) { 1 => 'map', true => 4, 'str' => true }
// 순서를 보장
const map4 = new Map([
[1, 'map'],
['str', true],
[true, 2],
])
console.log(map4) // Map(3) { 1 => 'map', 'str' => true, true => 2 }
Map은 객체와는 달리, 다양한 자료형을 키로 허용하지만 위와 같이 키가 중복될 경우, 객체와 마찬가지로 뒤에 있는 키의 값으로 덮어씌워 지는 것을 볼 수 있다.
즉, Map도 고유한 키를 가지는 것을 알 수 있다.
Map 메소드
set(key, value)
key를 이용해 value를 저장하는 메소드이다. 해당 key값이 있을 경우, value를 덮어씌운다. 또한 set은 반환값으로 자기 자신을 반환하기 때문에 chaining할 수 있다.
// set ( key, value )
const map = new Map();
map.set('1', 'map');
map.set(true, 2);
console.log(map); // Map(2) { '1' => 'map', true => 2 }
// 중복된 키 값
map.set('1', 'javascript');
console.log(map); // Map(2) { '1' => 'javascript', true => 2 }
// set chaining
const map1 = new Map();
map1.set('2', 'javascript').set(false, 'java').set(3, true);
console.log(map1); // Map(3) { '2' => 'javascript', false => 'java', 3 => true }
get(key)
해당 key 값의 value를 반환한다. 만약 key가 존재하지 않으면 undefined를 반환한다.
// get ( key )
const map = new Map([
['1', 'java'],
[true, false],
[2, 'hi'] // => 이하이...ㅎㅎ
]);
console.log(map.get(true)); // false
console.log(map.get('1')); // java
// key가 없으면?
console.log(map.get(false)); // undefined
has(key)
get과 유사하지만 has는 해당 key 값이 있으면 true, 없으면 false를 반환하는 메소드이다.
// has ( key )
const map = new Map([
['1', 'java'],
[true, false],
[2, 'hi'] // => 이하이...ㅎㅎ
]);
console.log(map.has(true)); // true
console.log(map.has('1')); // true
console.log(map.has(false)); // false
delete(key)
key에 해당하는 값을 삭제하는 메소드이다. 해당 키값을 삭제하면 true를 반환하고 해당 키가 없으면 false를 반환하다.
// delete ( key )
const map = new Map([
['1', 'java'],
[true, false],
[2, 'hi'] // => 이하이...ㅎㅎ
]);
if(map.delete(true)) {
console.log('delete succeeded')
}
if(!map.delete('2')) {
console.log('delete failed')
}
/* Result
delete succeeded
delete failed
*/
console.log(map); // Map(2) { '1' => 'java', 2 => 'hi' }
clear()
Map의 모든 요소를 제거한다.
// clear ()
const map = new Map([
['1', 'java'],
[true, false],
[2, 'hi'] // => 이하이...ㅎㅎ
]);
map.clear();
console.log(map); // Map(0) {}
size
Map이 가지고 있는 요소의 개수를 반환한다. 메소드는 아니기 때문에 소괄호()를 붙이지 않는다.
// size
const map = new Map([
['1', 'java'],
[true, false],
[2, 'hi'] // => 이하이...ㅎㅎ
]);
console.log(map.size); // 3
Map은 키로 객체도 허용
Map은 자료형의 제약이 없기 때문에 키로 객체도 허용한다.
const lang = {
name : 'javascirpt'
}
const map = new Map().set(lang, true);
console.log(map.get(lang)); //true
console.log(map); // Map(1) { { name: 'javascirpt' } => true }
Map의 요소에 반복 작업
Map은 해당 메소드를 이용하여 각 요소에 반복작업을 할 수 있다.
메소드 | 설명 |
keys() | 각 요소의 키를 모은 이터러블 객체를 반환 |
values() | 각 요소의 값을 모은 이터러블 객체를 반환 |
entries() | 요소의 키, 값을 한쌍으로 하는 이터러블 객체를 반환 |
Map은 순서를 보장한다는 특징을 가지고 있다. 이 말은 다른 말로, 요소가 삽입된 순서를 기억한다는 것이고 그렇기 때문에 이터러블한 특징을 가질 수 있다.
const map = new Map([
['1', 'java'],
[true, false],
[2, 'hi'] // => 이하이...ㅎㅎ
]);
for(let key of map.keys()) {
console.log(key); // '1' true 2
}
for(let value of map.values()) {
console.log(value); // 'java' false 'hi'
}
for(let entry of map.entries()) {
console.log(entry); // [ '1', 'java' ] [ true, false ] [ 2, 'hi' ]
}
// 내장 메소드 forEach도 지원
map.forEach((value, key, map) => {
console.log(`${key}: ${value}`);
});
Map <=> 객체 변환
객체를 Map으로 변환
Object.entries(객체)은 객체가 가지고 있는 키, 값을 2차원 배열로 반환하기 때문에 이를 이용하여 맵을 생성할 수 있다.
// 객체로 맵 만들기
let obj = {
name: "John",
age: 30
};
let map = new Map(Object.entries(obj)); // 객체를 2차원의 키:밸류 형태로 만들고 맵으로 변환
// [ ["name","John"], ["age", 30] ]
alert( map.get('name') ); // John
Map을 객체로 변환
Object.fromEntries를 사용하면 키, 값을 가지는 2차원 배열을 객체로 변환하여 준다. 자료가 맵에 저장되어있을 때, 자료를 객체 형태로 넘겨받으려 한다면 이 방법을 사용할 수 있다.
let map = new Map();
map.set('banana', 1);
map.set('orange', 2);
map.set('meat', 4);
let obj = Object.fromEntries(map.entries()); // 맵을 일반 객체로 변환 (*)
// let obj = Object.fromEntries(map); // .entries()를 생략할 수 있음.
// obj = { banana: 1, orange: 2, meat: 4 }
alert(obj.orange); // 2
reference : Inpa
'Programming > 자바스크립트' 카테고리의 다른 글
[자바스크립트] Symbol 타입 (0) | 2023.11.08 |
---|---|
[자바스크립트] Set 자료구조 (0) | 2023.11.08 |
[자바스크립트] 프로미스 - promise hell (0) | 2023.11.06 |
[자바스크립트] 프로미스 - 정적 메소드 (0) | 2023.11.06 |
[자바스크립트] 프로미스 - promise chaining (0) | 2023.11.06 |