Language/JavaScript

[모던 JavaScript] 5.8 위크맵과 위크셋

뚜sh뚜sh 2023. 2. 6. 11:20

위크맵

- 맵과 위크맵의 첫 번째 차이는 위크맵의 키가 반드시 객체여야 한다는 점임

- 원시값은 위크맵의 키가 될 수 없음

- 맵과 위크맵의 두 번째 차이는 위크맵은 반복 작업과 keys(), values(), entries() 메서드를 지원하지 않음, 따라서 위크맵에선 키나 값 전체를 얻는 게 불가능

- 이렇게 적은 메서드만 제공하는 이유는 가바지 컬렉션의 동작 방식 때문(동작 시점을 정확히 알 수 없어서)

let weakMap = new WeakMap();

let obj = {};

weakMap.set(obj, "ok"); //정상적으로 동작합니다(객체 키).

// 문자열("test")은 키로 사용할 수 없습니다.
weakMap.set("test", "Whoops"); // Error: Invalid value used as weak map key



let john = { name: "John" };

let weakMap = new WeakMap();
weakMap.set(john, "...");

john = null; // 참조를 덮어씀

// john을 나타내는 객체는 이제 메모리에서 지워집니다!

 

 

 

유스 케이스: 추가 데이터

- 위크맵은 부차적인 데이터를 저장할 곳이 필요할 때 그 진가를 발휘함

weakMap.set(john, "비밀문서");
// john이 사망하면, 비밀문서는 자동으로 파기됩니다.

 

 

 

유스 케이스: 캐싱

- 캐싱은 시간이 오래 걸리는 작업의 결과를 저장해서 연산 시간과 비용을 절약해주는 기법

// 📁 cache.js
let cache = new Map();

// 연산을 수행하고 그 결과를 맵에 저장합니다.
function process(obj) {
  if (!cache.has(obj)) {
    let result = /* 연산 수행 */ obj;

    cache.set(obj, result);
  }

  return cache.get(obj);
}

// 함수 process()를 호출해봅시다.

// 📁 main.js
let obj = {/* ... 객체 ... */};

let result1 = process(obj); // 함수를 호출합니다.

// 동일한 함수를 두 번째 호출할 땐,
let result2 = process(obj); // 연산을 수행할 필요 없이 맵에 저장된 결과를 가져오면 됩니다.

// 객체가 쓸모없어지면 아래와 같이 null로 덮어씁니다.
obj = null;

alert(cache.size); // 1 (엇! 그런데 객체가 여전히 cache에 남아있네요. 메모리가 낭비되고 있습니다.)


/*****************************위크맵을 사용한다면?*****************************/
// 📁 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;

// 이 예시에선 맵을 사용한 예시처럼 cache.size를 사용할 수 없습니다.
// 하지만 obj가 가비지 컬렉션의 대상이 되므로, 캐싱된 데이터 역시 메모리에서 삭제될 겁니다.
// 삭제가 진행되면 cache엔 그 어떤 요소도 남아있지 않을겁니다.

 

 

 

위크셋(WeakSet)

- 위크셋은 셋과 유사한데, 객체만 저장할 수 있다는 점이 다름, 원시값은 저장할 수 없음

- 셋 안의 객체는 도달 가능할 때만 메모리에서 유지됨

- 위크셋은 size, keys(), 반복 작업 관련 메서드는 사용할 수 없음

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); // 이어서 John이 다시 사이트를 방문합니다.

// visitedSet엔 두 명의 사용자가 저장될 겁니다.

// John의 방문 여부를 확인해보겠습니다.
alert(visitedSet.has(john)); // true

// Mary의 방문 여부를 확인해보겠습니다.
alert(visitedSet.has(mary)); // false

john = null;

// visitedSet에서 john을 나타내는 객체가 자동으로 삭제됩니다.

 

 

 

위크맵과 위크셋의 가장 큰 단점은 반복 작업이 불가능하다는 점임

위크맵과 위크셋은 객체와 함께 '추가' 데이터를 저장하는 용도로 쓸 수 있음