WeakMap, WeakSet 예제

항상 WeakMap, WeakSet을 어떤 방식으로 쓸까 많이 고민되었다.
참조가 없는 경우 메모리를 반환하는데에 이점이 있는데, 여러 활용방안이 있었다.

WeakMap

Cache

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 📁 cache.js
let cache = new WeakMap();

// calculate and remember the result
function process(obj) {
if (!cache.has(obj)) {
let result = /* calculate the result for */ obj;

cache.set(obj, result);
}

return cache.get(obj);
}

// 📁 main.js
let obj = {
/* some object */
};

let result1 = process(obj);
let result2 = process(obj);

// ...later, when the object is not needed any more:
obj = null;

Sealer

값을 봉인하고 box를 반환해 box object 전체가 와야만 내부값을 알 수 있게 해준다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function sealerFactory() {
const weakMap = new WeakMap();
return {
sealer(obj) {
const box = Object.freeze(Object.create(null));
weakMap.set(box, object);
return box;
},

unsealer(box) {
return weakMap.get(box);
},
};
}

WeakSet

Circular references

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// Execute a callback on everything stored inside an object
function execRecursively(fn, subject, refs = null) {
if (!refs) {
refs = new WeakSet();
}

// Avoid infinite recursion
if (refs.has(subject)) {
return;
}

fn(subject);
if (typeof subject === 'object') {
refs.add(subject);
for (let key in subject) {
execRecursively(fn, subject[key], refs);
}
}
}

const foo = {
foo: 'Foo',
bar: {
bar: 'Bar',
},
};

foo.bar.baz = foo; // Circular reference!
execRecursively((obj) => console.log(obj), foo);

참조

  • MDN WeakSet
  • The Modern JavaScript Tutorial - WeakMap
  • How JavaScript Works