Map
키와 값을 매핑하는 자료 구조로, ECMAScript 6 (ES6)부터 도입되었다. Map을 사용하면 데이터를 효과적으로 저장하고 검색할 수 있다. 다음과 같이 new 키워드를 사용해지만 생성할 수 있다. 만일 new 를 사용하지 않으면 typeerror 가 뜬다.
const examMap = new Map();
Map 의 특징
- 키와 값을 매핑하는 자료 구조로, 키와 값 모두 다양한 데이터 유형을 가질 수 있다.
- 키는 중복될 수 없다. 만일 중복된 키를 넣으려고 하면 마지막에 추가한 키의 값으로 업데이트 된다.
- 원소를 추가한 순서대로 순서를 보존한다.
- Map은 반복 가능한(iterable) 객체로, for...of 루프 등을 사용하여 순회할 수 있다.
이 때 오해하면 안 되는 점은 이터러블 객체이지 흔히 [ ] 와 같은 배열이 아니다. 그러므로 인덱스로 접근할 수 없다. |
Map의 메서드
- 값 추가하기 : Map에 값을 추가하려면 set() 메서드를 사용한다. set() 메서드는 키와 값을 받아서 매핑한다.
examMap.set('키1', '값1');
examMap.set('키2', '값2');
- 값 얻기: get() 메서드를 사용하여 특정 키에 대한 값을 얻을 수 있다.
const value = examMap.get('키1');
console.log(value); // 출력: '값1'
- 값 삭제하기: delete() 메서드를 사용하여 특정 키와 해당 값을 삭제할 수 있다.
examMap.delete('키1');
- 값 존재 여부 확인하기: has() 메서드를 사용하여 특정 키의 존재 여부를 확인할 수 있다.
const keyExists = examMap.has('키1');
console.log(keyExists); // 출력: false
- 크기 확인하기: size 프로퍼티를 사용하여 Map의 크기를 확인할 수 있다.
const mapSize = examMap.size;
console.log(mapSize); // 출력: 1 (키2와 해당 값만 남아 있음)
- 모든 키와 값 순회하기: for...of 루프를 사용하여 Map의 모든 키와 값을 순회할 수 있다.
for (const [key, value] of myMap) {
console.log(`${key}: ${value}`);
}
위에서 제시된 메소드 외에도 foreach, entries, keys 등 다양한 메소드를 사용할 수 있다.
요약) 간략하게 정리해보면, Map 은 순서를 보장하며, 이터러블 이므로 배열 메소드로 순회가 가능하다. 키는 중복이 불가능하므로, 중복된 키를 넣으려고 하면, 마지막에 추가한 키와 값으로 대체된다. |
Map의 장점
Map 은 일반적인 객체 생성 방식에 비해 성능상 이점이 있다. 특히, 키-값에 대한 빈번한 수정, 접근 등으로 인해 데이터의 규모가 커지는 상황에서는 그 차이는 더 벌어진다. 이는 내부적으로 Map의 경우에는 이러한 작업에 대한 최적화가 되어 있기 때문이며, 일반적인 객체 생성 방식에서는 키-값 쌍의 빈번한 추가 및 제거에 최적화되지 않는다.
Map 을 사용 시에는 보안적으로 일반적인 Object 프로토타입을 상속받아 생성된 객체 보다 우수하다. 왜냐 하면, Map의 경우에는 키로 사용될 수 있는 데이터 타입의 유형에 제한이 없기 때문에, 공격자로 하여금 키를 예측할 수 없게 하기 때문에 데이터 조작을 어렵게 만들기 때문이다.
또한, __proto__ 와 같이 프로토타입에 접근하는 것 자체를 제한하기 때문에, 공격자가 프로토타입의 상속을 조작하여 악의적인 코드 실행을 미연에 방지할 수 있다.
무엇보다 Map의 경우에는 저장된 객체에 접근하기 위해서 활용 가능한 메소드가 정해져 있다. 앞서 언급한 프로토타입의 변형 등으로 인한 잠재적인 보안 위험을 예방할 수 있다는 점에서 일반적인 객체 생성 방식에 비해 보안상 이점이 크다.
Map의 단점
일반적인 객체 방식에 비해서 개인적으로 큰 단점은 데이터의 직렬화와 역직렬화에 대한 지원이 없다는 점이다. 객체 리터럴 등으로 생성된 객체는 JSON.parse(), JSON.stringify() 를 통해 쉽게 데이터를 직렬화하고 역직렬화 가능하지만, Map은 그러한 메소드를 지원하지 않는다.
단, 이러한 문제를 개선하기 위한 방식으로 랩퍼 함수를 생성하여 처리하는 방법이 있는데,
replacer 와 reviver 라는 랩퍼 함수를 생성하고, stringify()의 두번째 인자에는 replacer 함수를 , parse()의 두번째 인자에는 reviver 함수를 전달하여 기존의 stringify와 parse 함수가 첫 번째 인자로 전달받은 값을 처리하는 프로세스를 대신 처리하도록 하여 수행할 수 있다.
function replacer(key, value) {
if(value instanceof Map) {
return {
dataType: 'Map',
value: Array.from(value.entries()), // or with spread: value: [...value]
};
} else {
return value;
}
}
function reviver(key, value) {
if(typeof value === 'object' && value !== null) {
if (value.dataType === 'Map') {
return new Map(value.value);
}
}
return value;
}
// 사용법 :
const originalValue = new Map([['a', 1]]);
const str = JSON.stringify(originalValue, replacer);
const newValue = JSON.parse(str, reviver);
console.log(originalValue, newValue);
// 배열, 객체, 맵의 조합을 통한 깊은 중첩
const originalValue = [
new Map([['a', {
b: {
c: new Map([['d', 'text']])
}
}]])
];
const str = JSON.stringify(originalValue, replacer);
const newValue = JSON.parse(str, reviver);
console.log(originalValue, newValue);
위 코드만 봐도 알겠지만, Map의 경우에는 직접 직렬화 및 역직렬화를 위한 대체 프로세스를 지정하는 함수를 인자로 넘겨 줘야지만 가능하기에 코드가 매우 더러워질 수 있다는 단점을 불가피해 보인다.
참고자료
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Map/Map
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
'자바스크립트' 카테고리의 다른 글
[javascript] reduce 메서드의 다양한 활용 (0) | 2023.11.10 |
---|---|
[JS] 자바스크립트에서 innerHTML 을 사용하지 말라고 하는 이유에 관한 정리 (0) | 2023.09.28 |
[JS] 자바스크립트의 렌더링 블록과 방지방법에 대한 정리(defer 와 async) (0) | 2023.09.23 |
[js] 클로저에 대한 정리 (2) | 2023.09.21 |
코드저장(인터섹션 옵저버 api) (0) | 2023.08.22 |