키 기반 컬렉션
키 기반 컬렉션 (Keyed collections)
이 장에서는 키(key)로 인덱싱되는 데이터 컬렉션을 소개합니다. Map과 Set 객체는 삽입 순서대로 반복(iterate) 가능한 요소들을 담고 있습니다.
본문
Maps
Map 객체
Map 객체는 요소를 삽입 순서대로 반복할 수 있는 키/값 맵(key/value map)입니다. 다음 코드는 Map을 사용하는 몇 가지 기본 연산을 보여줍니다. 더 많은 예제와 전체 API는 Map 참조 페이지를 참고하세요. for...of 루프를 사용하면 각 반복마다 [key, value] 배열을 얻을 수 있습니다.
const sayings = new Map();
sayings.set("dog", "woof");
sayings.set("cat", "meow");
sayings.set("elephant", "toot");
sayings.size; // 3
sayings.get("dog"); // woof
sayings.get("fox"); // undefined
sayings.has("bird"); // false
sayings.delete("dog");
sayings.has("dog"); // false
for (const [key, value] of sayings) {
console.log(`${key} goes ${value}`);
}
// "cat goes meow"
// "elephant goes toot"
sayings.clear();
sayings.size; // 0
Object와 Map 비교
전통적으로 객체(Object)는 문자열을 값에 매핑하는 데 사용되었습니다. 객체는 키에 값을 설정하고, 값을 검색하고, 키를 삭제하며, 특정 키에 무언가 저장되었는지 감지할 수 있습니다. 그러나 Map 객체는 더 나은 맵이 되게 하는 몇 가지 추가 장점이 있습니다.
Object의 키는 문자열 또는symbol인 반면,Map의 키는 임의의 값이 될 수 있습니다.Map의 크기(size)를 쉽게 얻을 수 있지만,Object는 크기를 직접 추적해야 합니다.- 맵의 반복은 요소의 삽입 순서대로 이루어집니다.
Object는 프로토타입을 가지므로 맵에 기본 키들이 존재합니다. (map = Object.create(null)을 사용하면 이를 우회할 수 있습니다.)
다음 세 가지 팁은 Map과 Object 중 무엇을 사용할지 결정하는 데 도움이 됩니다.
- 키가 런타임 시점까지 알려지지 않을 때, 특히 키가 외부 입력에서 오는 경우에는 객체보다 맵을 사용하세요.
Map은 모든 타입의 키와 값을 지원하며, 키가 문자열이나symbol로 직렬화 가능할 것을 요구하지 않습니다.- 모양(shape)이 미리 정해져 있고 모든 키가 문자열로 표현 가능할 때는 객체를 사용하세요.
WeakMap 객체
WeakMap은 키가 객체 또는 등록되지 않은 symbol이어야 하고, 값은 임의의 JavaScript 타입이 될 수 있으며, 키에 대한 강한 참조(strong reference)를 만들지 않는 키/값 쌍의 컬렉션입니다. 즉, 객체가 WeakMap의 키로 존재한다고 해서 그 객체가 가비지 컬렉션되지 않게 막지는 않습니다. 키로 사용된 객체가 수집되면, 해당 키에 연결된 WeakMap의 값들도 다른 곳에서 강하게 참조되지 않는 한 가비지 컬렉션의 대상이 됩니다. WeakMap 키로 사용할 수 있는 유일한 원시 타입(primitive type)은 symbol, 정확히는 등록되지 않은 symbol뿐입니다. 등록되지 않은 symbol은 고유함이 보장되고 다시 생성될 수 없기 때문입니다.
WeakMap API는 기본적으로 Map API와 동일합니다. 그러나 WeakMap은 키의 생존 여부(liveness)를 관찰하는 것을 허용하지 않으므로 열거(enumeration)를 지원하지 않습니다. 따라서 WeakMap에 있는 키 목록을 얻는 메서드는 없습니다. 만약 그런 메서드가 있다면, 그 목록은 가비지 컬렉션의 상태에 의존하게 되어 비결정성(non-determinism)이 생길 것입니다.
더 많은 정보와 예제 코드는 WeakMap 참조 페이지의 "Why WeakMap?"을 참고하세요.
WeakMap 객체의 한 가지 사용 사례는 객체의 전용(private) 데이터를 저장하거나 구현 세부 사항을 숨기는 것입니다. 다음 예제에서 전용 데이터와 메서드는 객체 내부에 속하며, privates라는 WeakMap에 저장됩니다. 인스턴스와 프로토타입에 노출된 것은 모두 공개적이고, 그 외의 모든 것은 privates가 모듈에서 내보내지지 않으므로 외부에서 접근할 수 없습니다.
const privates = new WeakMap();
export default function Public() {
const me = {
// Private data goes here
};
privates.set(this, me);
}
Public.prototype.method = function () {
const me = privates.get(this);
// Do stuff with private data in `me`
// …
};
참고: 이 사용 사례는 이제 클래스와 전용 필드(private fields)로 구현할 수 있습니다.
Sets
Set 객체
Set 객체는 고유한 값들의 컬렉션입니다. 요소를 삽입 순서대로 반복할 수 있습니다. Set의 값은 한 번만 존재할 수 있으며, Set 컬렉션 내에서 고유합니다.
다음 코드는 Set을 사용하는 몇 가지 기본 연산을 보여줍니다. 더 많은 예제와 전체 API는 Set 참조 페이지를 참고하세요.
const mySet = new Set();
mySet.add(1);
mySet.add("some text");
mySet.add("foo");
mySet.has(1); // true
mySet.delete("foo");
mySet.size; // 2
for (const item of mySet) {
console.log(item);
}
// 1
// "some text"
Array와 Set 간 변환
Array.from 또는 스프레드(spread) 문법을 사용해 Set으로부터 Array를 만들 수 있습니다. 또한 Set 생성자는 반대 방향으로 변환하기 위해 Array를 인자로 받습니다.
참고:
Set객체는 고유한 값만 저장하므로, 변환 시Array의 중복 요소는 삭제됩니다!
Array.from(mySet);
[...mySet2];
mySet2 = new Set([1, 2, 3, 4]);
Array와 Set 비교
전통적으로 많은 상황에서 요소들의 집합은 JavaScript에서 배열에 저장되어 왔습니다. 그러나 Set 객체는 몇 가지 장점이 있습니다.
- 값으로 배열 요소를 삭제하는 것(
arr.splice(arr.indexOf(val), 1))은 매우 느립니다. Set객체는 값으로 요소를 삭제할 수 있게 해줍니다. 배열에서는 요소의 인덱스를 기준으로splice해야 합니다.- 배열에서
NaN값은indexOf로 찾을 수 없습니다. Set객체는 고유한 값을 저장합니다. 중복을 수동으로 추적할 필요가 없습니다.
WeakSet 객체
WeakSet 객체는 객체와 등록되지 않은 symbol을 포함한 가비지 컬렉션 가능한 값들의 컬렉션입니다. WeakSet의 값은 한 번만 존재할 수 있으며, WeakSet 컬렉션 내에서 고유합니다.
Set 객체와의 주요 차이점은 다음과 같습니다.
Set과 달리WeakSet은 객체 또는 symbol만의 컬렉션이며, 임의의 타입 값의 컬렉션이 아닙니다.WeakSet은 약합니다(weak). 컬렉션에 있는 객체에 대한 참조는 약하게 유지됩니다.WeakSet에 저장된 객체에 대한 다른 참조가 없다면 가비지 컬렉션될 수 있습니다. 이는 또한 컬렉션에 저장된 현재 객체 목록이 없음을 의미합니다.WeakSet은 열거 가능하지 않습니다(enumerable).
WeakSet 객체의 사용 사례는 제한적입니다. 메모리를 누출하지 않으므로, 예를 들어 DOM 요소를 키로 사용해 추적 목적으로 표시하는 데 안전하게 사용할 수 있습니다.
Map과 Set의 키/값 동등성
Map 객체의 키 동등성과 Set 객체의 값 동등성은 모두 SameValueZero 알고리즘에 기반합니다.
- 동등성은 일치 연산자
===와 동일하게 동작합니다. -0과+0은 동등하게 간주됩니다.NaN은 자기 자신과 동등하게 간주됩니다(===와는 반대).