Map
Baseline
Widely available
*
This feature is well established and works across many devices and browser versions. It’s been available across browsers since 2015년 7월.
* Some parts of this feature may have varying levels of support.
Map 객체는 키-값 쌍과 키의 원래 삽입 순서를 기억합니다. 모든 값(객체 및
원시 값 모두)은 키 또는 값으로 사용될 수 있습니다.
시도해 보기
const map1 = new Map();
map1.set("a", 1);
map1.set("b", 2);
map1.set("c", 3);
console.log(map1.get("a"));
// Expected output: 1
map1.set("a", 97);
console.log(map1.get("a"));
// Expected output: 97
console.log(map1.size);
// Expected output: 3
map1.delete("b");
console.log(map1.size);
// Expected output: 2
설명
Map 객체는 키-값 쌍인 집합입니다. 한 Map에서의 키는 오직 단 하나만 존재 합니다. 이는 Map 집합의 유일성입니다.
Map 객체는 키-값 쌍으로 반복됩니다. for...of 루프는
각 반복에 대해 [key, value]로 이루어진 멤버가 2개인 배열을 반환합니다. 반복은 삽입한 순서대로 발생합니다. 즉,
set() 메서드로 맵에 처음
삽입한 각각의 키-값 쌍 순서와 대응됩니다. (set()이 호출되었을때 맵에서 해당 키가 없었을 경우입니다)
Map의 명세는 "평균적으로 집합 내 요소의 수에 따라 하위 선형인 접근 시간을 제공하는" 맵을 구현해야 한다고 기술되어 있습니다.
따라서 복잡성이 O(N)보다 더 나은 경우 내부적으로 해시 테이블(O(1) 룩업), 검색 트리(O(log(N)) 룩업) 또는 기타 데이터
구조로 표현될 수 있습니다.
키 동일성
값 동일성은 SameValueZero을
기반으로 합니다.(0과 -0을 다르게 취급하는 등가 같음을
사용하였습니다. 브라우저 호환성을 확인해보세요). 즉, NaN !== NaN에도 불구하고
NaN은 NaN과 동일하게 간주되며, 다른 모든 값은 === 연산자의 의미론에 따라 동일하게 간주됩니다.
객체 vs 맵
Object는 Map과 유사합니다. 둘 다 값을 가리키는 키를 설정하고, 해당 값을 받아오며, 키를 삭제하며,
키에 무언가가 저장되었는지 여부를 알 수 있습니다. 이러한 이유로 (그리고 대안으로 사용할 수 있는 내장 객체가 없었기 때문에)
Object는 역사적으로 Map으로 사용되어 왔습니다.
그러나 경우에 따라서는 아래와 같이 Map이 선호되는 중요한 차이점이 있습니다.
| Map | Object | |
|---|---|---|
| 우발적 키 |
Map는 기본적으로 키를 포함하지 않습니다. 여기에는 명시적으로 입력된 내용만 포함됩니다.
|
참고:
이는 |
| 보안 |
Map은 사용자가 제공하는 키와 값에 대해서 안전하게 사용할 수 있습니다.
|
사용자가 제공한 키-값 쌍을 |
| 키 유형 |
Map의 키는 모든 값(함수, 객체 또는 원시값 포함)이 될 수 있습니다.
|
Object의 키는 String 또는 Symbol이여야 합니다.
|
| 키 순서 |
|
일반적인
순서��� ECMAScript 2015에서만 자체 속성에 대해 처음 정의되었습니다.
ECMAScript 2020은 상속된 속성의 순서도 정의합니다.
OrdinaryOwnPropertyKeys
와
EnumerateObjectProperties
추상 명세작업을 참고하시기 바랍니다. 그러나 객체의 모든 속성을 반복하는 단일 메커니즘은 없습니다. 다양한 메커니즘에는 각각 다른 속성 하위 집합이 포함됩니다
( |
크기 |
Map의 아이템의 수는 size 속성에서 쉽게 가져올 수 있습니다.
|
Object의 아이템 수는 수동으로 결정해야 합니다.
|
| 순회 |
Map은
순회가능(iterable)하기 때문에 이므로 직접 반복할 수 있습니다.
|
참고:
|
| 성능 |
키-값 쌍의 빈번한 추가 및 제거와 관련된 상황에서는 성능이 좀 더 좋습니다. |
키-값 쌍의 빈번한 추가 및 제거에 최적화되지 않았습니다. |
| Serialization and parsing |
직렬화 또는 구문 분석에 대한 기본 지원이 없습니다.
(하지만 |
|
객체 속성 설정하기
객체 속성 설정은 Map 객체에서도 작동하지만 상당한 혼란을 야기할 수 있습니다.
따라서 이는 다음과 같은 방식으로 동작하는 것처럼 보입니다.
const wrongMap = new Map();
wrongMap["bla"] = "blaa";
wrongMap["bla2"] = "blaaa2";
console.log(wrongMap); // Map { bla: 'blaa', bla2: 'blaaa2' }
그러나 속성을 설정하는 방법은 Map 데이터 구조와 상호 작용하지 않습니다. 속성 설정은 일반 객체의 기능을 사용��니다. 'bla' 값은 질의를 위한 Map에 저장되지 않습니다. 데이터에 대한 다른 작업도 아래와 같이 실패합니다.
wrongMap.has("bla"); // false
wrongMap.delete("bla"); // false
console.log(wrongMap); // Map { bla: 'blaa', bla2: 'blaaa2' }
맵에 데이터를 저장하는 올바른 방법은 set(key, value) 메서드를 사용하는 것입니다.
const contacts = new Map();
contacts.set("Jessie", { phone: "213-555-1234", address: "123 N 1st Ave" });
contacts.has("Jessie"); // true
contacts.get("Hilary"); // undefined
contacts.set("Hilary", { phone: "617-555-4321", address: "321 S 2nd St" });
contacts.get("Jessie"); // {phone: "213-555-1234", address: "123 N 1st Ave"}
contacts.delete("Raymond"); // false
contacts.delete("Jessie"); // true
console.log(contacts.size); // 1
생성자
Map()-
새로운
Map객체를 생성합니다.
정적 속성
get Map[@@species]-
파생 객체를 만드는 데 사용되는 생성자 함수입니다.
인스턴스 속성
Map.prototype[@@toStringTag]-
@@toStringTag속성의 초기 값은 문자열"Map"입니다. 이 속성은Object.prototype.toString()에서 사용합니다. Map.prototype.size-
Map객체의 키/값 쌍의 숫자를 반환합니다.
인스턴스 메서드
Map.prototype.clear()-
Map객체에서 모든 키-값 쌍을 제거합니다. Map.prototype.delete()-
Map객체에 해당 요소가 존재하며 삭제되었을 경우true를 반환하며 해당 요소가 존재하지 않는 경우false를 반환합니다. 이 이후에map.has(key)를 실행하면false를 반환할 것입니다. Map.prototype.get()-
주어진 키에 해당하는 값을 반환하거나 값이 없다면
undefined을 반환합니다. Map.prototype.has()-
주어진 키에 연관된 값이
Map객체에 존재하는지 여부를 불리언 값으로 반환합니다. Map.prototype.set()-
Map객체에서 전달된 키의 값을 설정합니다.Map객체를 반환합니다. Map.prototype[@@iterator]()-
Map객체에 삽입된 순서에 따라[key, value]두 개의 멤버 배열을 포함하는 새로운 반복자를 반환합니다. Map.prototype.keys()-
Map객체에 삽입된 순서에 따라 각 요소의 키를 포함하는 새로운 반복자를 반환합니다. Map.prototype.values()-
Map객체에 삽입된 순서에 따라 각 요소의 값을 포함하는 새로운 반복자를 반환합니다. Map.prototype.entries()-
Map객체에 삽입된 순서에 따라[key, value]두 개의 멤버 배열을 포함하는 새로운 반복자를 반환합니다. Map.prototype.forEach()-
Map객체에 존재하는 각 키-값 쌍에 대해 삽입 순서대로callbackFn을 한 번씩 호출 합니다. 만약forEach호출 시thisArg매개변수가 있다면 각 콜백의this값으로 사용됩니다.
예제
Map 객체 사용하기
const myMap = new Map();
const keyString = "a string";
const keyObj = {};
const keyFunc = function () {};
// 값 설정
myMap.set(keyString, "value associated with 'a string'");
myMap.set(keyObj, "value associated with keyObj");
myMap.set(keyFunc, "value associated with keyFunc");
console.log(myMap.size); // 3
// 값 불러오기
console.log(myMap.get(keyString)); // "value associated with 'a string'"
console.log(myMap.get(keyObj)); // "value associated with keyObj"
console.log(myMap.get(keyFunc)); // "value associated with keyFunc"
console.log(myMap.get("a string")); // "value associated with 'a string'", 왜냐하면 keyString === 'a string'
console.log(myMap.get({})); // undefined, 왜냐하면 keyObj !== {}
console.log(myMap.get(function () {})); // undefined, 왜냐하면 keyFunc !== function () {}
Map 키로 NaN 사용하기
NaN도 키로 사용할 수 있습니다. 모든 NaN이 자신과 같지는 않지만(NaN !== NaN은 참입니다), NaN은 서로 구별할 수 없기 때문에 다음과 같은 예시가 동작합니다.
const myMap = new Map();
myMap.set(NaN, "not a number");
myMap.get(NaN);
// "not a number"
const otherNaN = Number("foo");
myMap.get(otherNaN);
// "not a number"
for...of로 맵 순회하기
맵은 for...of 반복을 사용하여 순회할 수 있습니다.
const myMap = new Map();
myMap.set(0, "zero");
myMap.set(1, "one");
for (const [key, value] of myMap) {
console.log(`${key} = ${value}`);
}
// 0 = zero
// 1 = one
for (const key of myMap.keys()) {
console.log(key);
}
// 0
// 1
for (const value of myMap.values()) {
console.log(value);
}
// zero
// one
for (const [key, value] of myMap.entries()) {
console.log(`${key} = ${value}`);
}
// 0 = zero
// 1 = one
forEach()로 맵 순회하기
맵은 forEach() 메서드를 사용하여 순회할 수 있습니다.
myMap.forEach((value, key) => {
console.log(`${key} = ${value}`);
});
// 0 = zero
// 1 = one
배열 객체와의 관계
const kvArray = [
["key1", "value1"],
["key2", "value2"],
];
// Use the regular Map constructor to transform a 2D key-value Array into a map
const myMap = new Map(kvArray);
console.log(myMap.get("key1")); // "value1"
// Use Array.from() to transform a map into a 2D key-value Array
console.log(Array.from(myMap)); // Will show you exactly the same Array as kvArray
// A succinct way to do the same, using the spread syntax
console.log([...myMap]);
// Or use the keys() or values() iterators, and convert them to an array
console.log(Array.from(myMap.keys())); // ["key1", "key2"]
맵 복제하기와 병합하기
Array와 같이 Map은 복제가 가능합니다.
const original = new Map([[1, "one"]]);
const clone = new Map(original);
console.log(clone.get(1)); // one
console.log(original === clone); // false (useful for shallow comparison)
참고 : 데이터 자체는 복제가 안된다는 사실을 명심하셔야 합니다.
맵은 키 유일성을 유지한채로 병합이 가능합니다.
const first = new Map([
[1, "one"],
[2, "two"],
[3, "three"],
]);
const second = new Map([
[1, "uno"],
[2, "dos"],
]);
// 두 맵을 병합합니다. 키 값이 중복될 경우 마지막 키의 값을 따릅니다.
// 전개 문법은 맵을 배열로 변환합니다.
const merged = new Map([...first, ...second]);
console.log(merged.get(1)); // uno
console.log(merged.get(2)); // dos
console.log(merged.get(3)); // three
맵은 배열과 병합될 수 있습니다.
const first = new Map([
[1, "one"],
[2, "two"],
[3, "three"],
]);
const second = new Map([
[1, "uno"],
[2, "dos"],
]);
// 맵을 배열로 병합하기. 중복된 키가 있다면 마지막에 병합된 맵의 키에 해당하는 값이 설정됩니다.
const merged = new Map([...first, ...second, [1, "eins"]]);
console.log(merged.get(1)); // eins
console.log(merged.get(2)); // dos
console.log(merged.get(3)); // three
명세
| Specification |
|---|
| ECMAScript® 2027 Language Specification # sec-map-objects |