[JAVASCRIPT.INFO] 5.8 위크맵과 위크셋
5.8 위크맵과 위크셋
let john = {name: "John"};
let map = new Map();
map.set(john, '...');
john = null; // 참조를 null로 덮어씀
// john을 나타내는 객체는 맵 안에 저장되어있다.
// map.keys()를 이용하면 해당 객체를 얻는 것이 가능하다.
for(let obj of map.keys()){
alert(JSON.stringify(obj));
}
alert(map.size);
맵에서 객체를 키로 사용한 경우, 맵이 메모리에 있는 한 객체도 메모리에 남는다.(가비지 컬렉터의 대상이 되지 않는다.)
하지만 WeakMap
은 다른 양상을 띄운다.
위크맵
위크맵의 키는 반드시 객체여야 한다. (원시값은 위크맵의 키가 될 수 없다.)
let weakMap = new WeakMap(); let obj = {}; weakMap.set(obj, "ok"); // 정상적으로 동작함 // 문자열 ("test")는 키로 사용할 수 없음 weakMap.set("test", "Whoops"); // Error
위크맵의 키로 사용된 객체를 참조하는 것이 아무것도 없다면 해당 객체는 메모리와 위크맵에서 자동으로 삭제된다.
let joh = { new: "John" }; let weakMap = new WeakMap(); weakMap.set(john, "..."); john = null; // 참조를 덮어씀 // john을 나타내는 객체는 이제 메모리에서 지워진다.
위크맵은 반복작업과,
keys()
,values()
,entries()
메서드를 지원하지 않는다. 위크맵이 지원하는 메서드는 4가지이다. (지원하는 메서드가 적은 이유는 객츠는 모든 참조를 잃게 되면 가비지 컬렉션의 대상이 되기 때문이다. 가비지 컬렉션의 동작 시점은 정확히 알 수 없으므로 메서드 동작 자체가 불가하다.)weakMap.get(key)
weakMap.set(key, value)
weakMap.delete(key)
- weakMap.has(key)`
Use Case: 추가 데이터
위크맵은 부차적인 데이터를 저장할 곳이 필요할 때 사용한다.
서드파티 라이브러리와 같은 외부 코드에 '속한' 객체를 가지고 작업을 해야 한다고 가정할 때, 이 객체에 데이터를 추가하는 동작을 할 시 추가해 줄 데이터는 객체가 살아있는 동안에만 유효하다. 이런 경우 위크맵을 사용할 수 있다.
weakMap.set(john, "비밀문서");
// john이 사망하면, 비밀문서는 자동으로 파기된다.
사용자의 방문횟수를 카운트할 때, 사용자의 정보를 저장할 필요가 없어지면 해당 사용자의 방문 횟수도 저장할 필요가 없어지게 된다.
// visitCount.js
let visitsCountMap = new WeakMap();
function countUser(user) {
let count = visitsCountMap.get(user) || 0;
visitsCountMap.set(user, count+1);
}
// main.js
let john = {name: "John"};
countUser(john); // John의 방문 횟수를 증가시킴
// John의 방문 횟수를 셀 필요가 없어지면, john을 null로 덮어씌운다.
john = null;
위크맵을 사용해 사용자 방문 횟수를 지정하면 visitsCountMap
을 수동으로 청소해줄 필요가 없다. john
을 나타내는 객체가 도달 가능하지 않은 상태가 되면 자동으로 메모리에서 삭제되기 때문이다. 위크맵의 키에 대응하는 값 (john의 방문 횟수)도 자동으로 가비지 컬렉션의 대상이 된다.
Use Case: 캐싱
위크맵은 캐싱이 필요할 때 유용하다.
// cache.js
let cache = new WeakMap();
// 연산을 수행하고 그 결과를 위크맵에 저장
function process(obj) {
if(!cache.has(obj)){
let result = /*연산 수행*/obj;
cache.set(obj, result);
}
return cache.get(obj);
}
// main.js
let obj = {/* ... 객체 ... */};
let result1 = process(obj);
let result2 = process(obj);
// 객체가 필요 없어지면 아래와 같이 null로 덮어쓴다.
obj = null;
// obj가 가비지 컬렉션의 대상이 되므로, 캐싱된 데이터 역시 메모리에서 삭제됨
// 삭제가 진행되면 cache엔 아무 요소도 남아있지 않게됨
위크셋
- 위크셋은 셋과 유사하지만, 객체만 저장할 수 있다.
- 셋 안의 객체는 도달 가능할 때만 메모리에서 유지된다.
- 위크셋이 지원하는 메서드는
add
,has
,delete
이다.
위크맵과 유사하게 위크셋도 부차적인 데이터를 저장할 때 사용할 수 있다. 다만, 위크셋엔 위크맵처럼 복잡한 데이터를 저장하지 않고 간단한 답변을 얻어내는 용도로 사용한다.
let visitedSet = new WeakSet();
let john = {name: "John"};
let pete = {name: "Pete"};
let mary = {name: "Mary"};
visitedSet.add(john); // john이 사이트 방문
visitedSet.add(pete); // pete가 사이트 방문
visitedSet.add(john); // johnd이 다시 사이트 방문
alert(visitedSet.has(john)); // true;
alert(visitedSet.has(mary)); // false