知名度が低いウェブ標準ひとり Advent Calendar 2021 – 09 日目

ES 6 こと ES2015 で Proxy というのが追加されました。あらゆるプロパティへのアクセスを制御できます。存在しないプロパティへのアクセスも捉えて存在するように振る舞うことも可能。

基本的な使い方

コンストラクターの第 2 引数で get() や set() なんかを設定します。

const original = { hi: 'hi' };
const proxy = new Proxy(original, {
  get(obj, prop) {
    if (prop in obj) {
      return obj[prop];
    }

    if (prop === 'ho') {
      return 'ho';
    }

    return Math.floor(Math.random() * 100); // 0-99
  }
});

console.log('random:', proxy.hi, proxy.ho, proxy.yo);
console.log('random:', proxy.hi, proxy.ho, proxy.yo);
console.log('random:', proxy.hi, proxy.ho, proxy.yo);
random: hi ho 8
random: hi ho 94
random: hi ho 39

何かのインスタンスを wrap して、プロパティアクセスがあるたびに get() がそれを trap します。アクセスしたプロパティ名を判断して好きな値を返したりすることができるようになります。

hi は original.hi として存在するので proxy.hi は元の値を返します。ho へのアクセスは常に "ho" を、またそれ以外の値は全てランダムな数値を返すようにしました。

なお original 自体は変化ありません。

使いどころ

バグで意図せず値が変わってしまうような現象がおきているとき、この Proxy で wrap したオブジェクトと差し替え、set() でログ出力したりしてデバッグしたことがあります。(オブジェクトを差し替えるのを忘れないように!)

あとは Ruby on Rails の ActiveRecord みたいに存在するフィールドに対する getter/setter を自動で用意することができそうです。やったことはない。

おしまい

すげー強力だとは思います。