자바스크립트로 개발하면서 가장 많이 사용하게 되는 자료구조에는 객체와 배열이 있다. 객체는 키가 있는 컬렉션을 저장할 수 있고, 배열은 순서가 있는 컬렉션을 저장한다. 하지만 점차 복잡해져가는 소프트웨어 시장속에서 위의 두 자료구조만으로 개발하기에는 코드가 많이 복잡해짐에 따라 맵(Map)과 셋(Set)이 등장하게 됐다. (Set에 관해서는 다음 포스팅에서 다뤄볼 예정이다)
맵 (Map)
맵은 키가 있는 데이터를 저장한다는 관점에서는 객체와 유사하다. 하지만 맵은 키에 다양한 자료형을 허용한다는 점에서 차이가 있다.
아래의 코드처럼 다양한 자료형을 Key에 사용할 수 있다.
let map = new Map();
map.set('1', '1'); // 문자 Key
map.set(1, 'one'); // 숫자 key
map.set(true, 'bool_true'); // Boolean Key
맵의 메서드
위의 코드에서 볼 수 있듯 맵을 사용할 때는 메서드를 활용한다. 아래는 map의 주요 메서드 및 프로퍼티 목록이다.
- new Map()
맵을 만든다. - map.set(key, value)
key값에 해당하는 value를 저장한다. 반환값은 맵 자신이다. - map.get(key)
key에 해당하는 value를 반환한다. key가 존재하지 않는 경우 undefined를 반환한다. - map.has(key)
key값이 있는지 확인한다. 존재하면 true, 존재하지 않는다면 false를 반환한다. - map.delete(key)
key와 해당하는 값을 삭제한다 - map.clear()
맵 안의 모든 데이터를 삭제한다. - map.size
맵에 저장된 사이즈를 반환한다. - map.keys()
각 요소의 key를 모은 iterable 객체를 반환한다. - map.values()
각 요소의 value를 모은 iterable 객체를 반환한다. - map.entries()
요소의 [key, value]를 한 쌍으로 하는 iterable 객체를 반환한다. 이 객체는 for..or 반목문의 기초로 사용된다.
맵을 사용하면서 주의해야 할 사항은, 맵은 객체와 달리 키를 문자형으로 반환하지 않는다는 점이다. 키에는 자료형 제약이 없기 때문이다.
map[key] = value 와 같이 설정하는 방법을 사용할 수 있지만, 이렇게 사용했을 경우 map을 일반 객체처럼 취급하게 되어 여러 제약이 생기게 된다. 따라서 map을 사용할 때에는 get, set등의 메서드를 사용해야 한다.
객체를 키로 활용하기
맵은 다양한 자료형을 키로 사용할 수 있는데, 객체 역시 허용한다. 키엔 자료형의 제약이 없다.
let spr = { name: "soopiri" };
let moneyMap = new Map();
moneyMap.set(spr, 10000);
console.log(moneyMap.get(spr)); // 10000
객체를 키로 사용할 수 있다는 것은 맵의 활용도를 확장시켜주는 가장 중요한 기능 중 하나이다. 객체에는 문자열 키를 사용할 수 있지만 객체 키는 사용할 수 없다. 객체형 키를 객체에 사용하면 어떻게 될까? 아래 코드를 살펴보자.
let spr = { name: 'soopiri' };
let moneyObj = {};
moneyObj[spr] = 10000
// moneyObj는 객체이기 때문에 모든 키를 문자형으로 변환시킨다.
// 이 과정에서 spr은 문자형으로 변환되어 '[object Object]'로 변한다.
// 이 때문에 객체는 객체키를 사용할 수 없다.
console.log(moneyObj['[obejct Object]'])
맵의 key 비교 알고리즘
맵은 SameValueZero라고 불리는 알고리즘을 통해 값의 등가 여부를 확인한다. 이 알고리즘은 일치 연산자 (===)와 거의 비슷하지만, NaN과 NaN을 같다고 취급하는 것에서 일치 연산자와는 차이가 있다. 이 말은 맵에선 NaN도 키 값으로 활용할 수 있다.
SameValueZero 알고리즘은 수정 및 커스티마이징이 불가능하다.
Chaining
map.set의 반환 값은 맵 자신이다. 이를 활용하여 map.set 메서드를 체이닝 할 수 있다.
// example map chaining
map.set('s', 'soo').set(1, 'one').set(true, '참');
맵의 요소에 반복 작업하기
위에서 언급한 keys(), values(), entries() 메서드를 통해, 맵의 각 요소에 반복 작업을 할 수 있다. 아래 코드를 살펴보자.
let priceMap = new Map([
['iPhone', 1300], ['iPad', 1500], ['macbook', 3000]
]);
// key iterate
for (let product of priceMap.keys()){
console.log(product) // iPhone, iPad, macbook
}
// value iterate
for (let price of priceMap.values()){
console.log(price) // 1300, 1500, 3000
}
// [key, value] iterate
for (let pp of priceMap) {
console.log(pp)
// ['iPhone', 1300]
// ['iPad', 1500]
// ['macbook', 3000]
}
// foreach loop
priceMap.forEach( (value, key, map) => {
console.log(value)
});
맵의 삽입 순서
맵은 값이 삽입(set) 된 순서를 기억하여 순서대로 반복한다. 객체가 Property의 순서를 기억하지 못하는 것과 다른 모습이다.
객체를 맵으로 바꾸기 (Object.entries)
위에서 살펴본 바와 같이 각 요소가 key, value 쌍인 iterable 객체 또는 배열을 초기화 용도로 맵에 전달하여 맵을 만들 수 있다.
더 나아가 평범한 객체를 가지고 맵을 만들고 싶다면 Object.entries(obj) 내장 함수를 활용하면 된다. 이 함수는 객체의 key, value 쌍을 [key, value]를 요소로 가지는 배열을 반환한다.
let obj = {
name: 'soopiri',
age: 99
}
let map = new Map(Object.entries(obj));
console.log(map.get('name')) // soopiri
Object.entries 함수를 통해 객체 obj를 배열 [['name', 'soopiri'], ['age', 99]]로 변경하여, 해당 배열을 이용해 맵을 만든 코드이다.
맵을 객체로 바꾸기 (Object.fromEntries)
반대로, 맵을 객체로 바꾸는 방법도 있다. Object.fromEntries 메서드를 활용하여 각 요소가 [key, value]쌍인 배열을 객체로 변경해준다.
let map = new Map();
map.set('s', 'o');
map.set('p', 'i');
map.set('r', 'i');
// change map to normal object
let obj = Object.fromEntries(map.entries());
// obj = {s: 'o', p: 'i', r: 'i' }
마무리하며..
맵(Map)은 Key가 있는 Value가 저장된 Collection이며, 메소들을 활용하여 사용한다. 일반적인 객체와의 차이점은 Key값의 타입에 제약이 없으며 객체 역시 Key가 될 수 있다. size등의 유영한 method나 property를 활용할 수 있다.
참고링크
'Development > JavaScript' 카테고리의 다른 글
Javascript - 원시값(Primitive)의 메서드 (0) | 2022.04.27 |
---|---|
Javascript - Set을 알아보자 (0) | 2022.04.27 |
구조 분해 할당(Destructuring Assignment) - 객체, 중첩구조 편 (0) | 2022.04.26 |
구조 분해 할당(Destructuring Assignment) - 배열편 (0) | 2022.04.25 |
콜백지옥 (Callback Hell)과 비동기(async) 처리 (0) | 2022.04.23 |