【JavaScript】WeakMap オブジェクトを理解する

WeakMap JavaScript

スポンサーリンク

WeakMap オブジェクトとは

WeakMap オブジェクトは、Object オブジェクトや Map オブジェクトと同様に、key / value のペアのコレクション(データの集まり)を作成するためのオブジェクトであり、ES6(ES2015)で導入された。

WeakMap は次のような特徴を持っている。

  • キー(key)はオブジェクトでなければならない。
  • キーに指定したオブジェクトが他から参照されなくなるとガベージコレクションの対象になる。つまり自動的にメモリから(WeakMap からも)いつか削除される。
  • 反復可能ではなく、全てのキーや値を取得する方法はない。つまり WeakMap 自体からはキーを取得することはできない。
  • 値(value)は任意の型でよい。

WeakMap コンストラクタ

WeakMap オブジェクトはその他の多くの組み込みオブジェクトと同様にコンストラクタ関数であり、次のサンプルようにしてインスタンスを生成することができる。コンストラクタの引数には、キーと値のペアを要素とする反復可能オブジェクトを渡すことができる。(参考:MDN

// 空の weakmap を生成
const wm1 = new WeakMap();

// キーと値のペアを与えて生成
let key1 = {};
let key2 = [1, 3];
let key3 = new Set();
const wm2 = new WeakMap([
  [key1, 'value1'],
  [key2, 'value2'],
  [key3, 'value3'],
])

WeakMap のメソッド

WeakMap オブジェクトには次の4つのインスタンスメソッドが存在する。(以下の wm は WeakMap のインスタンスを表す)

  • wm.get(key)
  • wm.set(key, value)
  • wm.has(key)
  • wm.delete(key)
// 空の weakmap を生成
const wm = new WeakMap();

const key = {}

console.log(wm.has(key)); // false
wm.set(key, [1, 2, 3]);
console.log(wm.has(key)); // true
console.log(wm.get(key)); // [1, 2, 3]

wm.delete(key);
console.log(wm.has(key)); // false
console.log(wm.get(key)); // undefined

WeakMap によるプライベートプロパティ

WeakMap オブジェクトを使用すると、クラス定義においてプライベートなプロパティを実現できる。(参考:MDN

const Person = (function() {
  const wm = new WeakMap();

  return class Person {
    constructor(nickname, name, age) {
      this.nickname = nickname;
      // private プロパティは wm に格納
      wm.set(this, {
        name,
        age
      })
    }
  
    profile() {
      const privateObj = wm.get(this);
      console.log(`nickname: ${this.nickname}`);
      console.log(`name: ${privateObj.name}`);
      console.log(`age: ${privateObj.age}`);
    }
  }
})();

const person = new Person('ta', 'taro', 31);
person.profile();
// nickname: ta
// name: taro
// age: 31
console.log(person.nickname);
// ta
console.log(person.name);
// undefined
console.log(person.age);
// undefined

生成されたインスタンスからは、コンストラクタの中で this に格納したプロパティにしかアクセスできない。また、private なプロパティを格納している WeakMap のオブジェクト wm には、即時関数のスコープ外からはアクセスできない。そのため、即時関数の外部からは private なプロパティは完全に隠蔽される。

一方で、即時関数の中を注目してみると、キーや値を列挙できないという WeakMap が持つ性質、つまり WeakMap 自体からはキーを取得できないという性質のために、private なプロパティを wm から引き出すためには、そのキーであるインスタンスを知っている必要がある。そしてそれを唯一 this として知っているのがクラス定義の内部となっている。したがってクラスの外部からも private なプロパティは完全に隠蔽されている。

そしてクラスから生成されたインスタンスが参照されなくなれば、WeakMap に残っている private なプロパティはガベージコレクションの対象になり、いずれ削除されることになる。そのためメモリリークの心配をする必要がない。

このように WeakMap はクラスのプライベートプロパティを定義するための方法として使用することができる。

スポンサーリンク

タイトルとURLをコピーしました