Posts 모던 자바스크립트 #5.8. 위크맵과 위크셋
Post
Cancel

모던 자바스크립트 #5.8. 위크맵과 위크셋

모던 JavaScript 튜토리얼을 따라가면서 정리합니다.

위크맵

  • 맵에서 객체를 키로 사용한 경우 맵이 메모리에 있는 한 객체도 메모리에 남는다. 가비지 컬렉터의 대상이 아니다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    
    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())
    
  • 그러나 위크맵을 사용하면 키로 사용된 객체를 참조하는 것이 아무것도 없다면 해당 객체는 메모리와 위크맵에서 자동으로 삭제된다.

    1
    2
    3
    4
    
    let john = { name: "John" };
    let weakMap = new WeakMap();
    weakMap.set(john, "...");
    john = null;
    
  • 위크맵과 유사한 컬렉션이다. 위크맵을 구성하는 요소의 키는 오직 객체만 가능하다. 키로 사용된 객체가 메모리에서 삭제되면 이에 대응하는 값 역시 삭제된다.

  • 위크맵이 지원하는 메서드: get, set, delete, has

  • 위크맵이 적은 메서드만 지원하는 이유: 가비지 컬렉션 때문이다. 객체는 모든 참조를 잃게 되면 자동으로 가비지 컬렉션의 대상이 되는데 가비지 컬렉션의 동작 시점은 정확히 알 수 없다. 현재 위크맵에 요소가 몇 개 있는지 파악하는 것도, 위크맵의 요소 전체를 대상으로 무언가를 하는 동작 자체도 불가능한 이유이다. 가비지 컬렉터가 한 번에 메모리를 청소할 수도 있고, 부분 부분 메모리를 청소할 수도 있기 때문이다.

  • 위크맵의 유스케이스

    • 추가 데이터: 부차적인 데이터를 저장할 곳이 필요할 때

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

      맵을 사용해 사용자 방문 횟수를 저장한다고 해보자. 어떤 사용자의 정보를 저장할 필요가 없어지면(가비지 컬렉션의 대상이 되면) 해당 사용자의 방문 횟수도 저장할 필요가 없어진다.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      
      // 📁 visitsCount.js
      let visitsCountMap = new Map(); // 맵에 사용자의 방문 횟수를 저장함
          
      // 사용자가 방문하면 방문 횟수를 늘려줍니다.
      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;
      

      null로 덮어줘도 visitsCountMap의 키로 사용되고 있어서 메모리에서 삭제되지 않는다. 우리가 손수 지워주지 않으면 visitsCountMap은 한없이 커질텐데, 앱이 복잡할 땐 이렇게 쓸모 없는 데이터를 수동으로 바꿔주는 것이 골치아프다. 이때 위크맵을 사용하면 수동으로 청소해줄 필요가 없다.

    • 캐싱: 시간이 오래 걸리는 작업의 결과를 저장해서 연산 시간과 비용을 절약해준다.

      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
      
      // 📁 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에 어떤 요소도 남지 않을 것이다. 단, size 프로퍼티는 이용할 수 없다.

위크셋

  • 위크셋과 유사한 컬렉션이다. 위크셋엔 객체만 저장할 수 있다. 위크셋에 저장된 객체가 도달 불가능한 상태가 되면 해당 객체는 메모리에서 삭제된다.

  • 위크셋엔 위크맵처럼 복잡한 데이터를 저장하지 않는다. 대신 ‘예’나 ‘아니오’ 같은 간단한 답변을 얻는 용도로 사용된다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
    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을나타내는 객체가 자동으로 삭제됩니다.
    

두 자료구조 모두 구성 요소 전체를 대상으로 하는 메서드를 지원하지 않는다. 구성 요소 하나를 대상으로 하는 메서드만 지원한다.

객체에는 ‘주요’ 자료를, 위크맵위크셋에는 ‘부수적인’ 자료를 저장하는 형태로 위크맵과 위크셋을 활용할 수 있다. 객체가 메모리에서 삭제되면, 그리고 오로지 위크맵과 위크셋의 키만 해당 객체를 참조하고 있다면 위크맷이나 위크셋에 저장된 연관 자료들 역시 메모리에서 자동으로 삭제된다.

This post is licensed under CC BY 4.0 by the author.

모던 자바스크립트 #5.7. 맵과 셋

HIWORK: Field 'cNo' doesn't have a default value

Loading comments from Disqus ...