レッスンに戻る

Observable

プロキシを返して「オブジェクトをオブザーバブルにする」makeObservable(target)という関数を作成します。

機能は次のようになります。

function makeObservable(target) {
  /* your code */
}

let user = {};
user = makeObservable(user);

user.observe((key, value) => {
  alert(`SET ${key}=${value}`);
});

user.name = "John"; // alerts: SET name=John

つまり、makeObservableによって返されるオブジェクトは元のオブジェクトと同じですが、任意のプロパティの変更時に呼び出されるhandler関数を設定するobserve(handler)メソッドも追加されています。

プロパティが変更されるたびに、handler(key, value)はプロパティの名前と値で呼び出されます。

P.S. このタスクでは、プロパティへの書き込みのみを処理してください。他の操作は同様の方法で実装できます。

解決策は2つの部分で構成されています。

  1. .observe(handler)が呼び出されるたびに、後で呼び出すことができるように、ハンドラをどこかに記録する必要があります。シンボルをプロパティキーとして使用して、ハンドラをオブジェクト内に直接格納できます。
  2. 変更時にハンドラを呼び出すには、setトラップを使用したプロキシが必要です。
let handlers = Symbol('handlers');

function makeObservable(target) {
  // 1. Initialize handlers store
  target[handlers] = [];

  // Store the handler function in array for future calls
  target.observe = function(handler) {
    this[handlers].push(handler);
  };

  // 2. Create a proxy to handle changes
  return new Proxy(target, {
    set(target, property, value, receiver) {
      let success = Reflect.set(...arguments); // forward the operation to object
      if (success) { // if there were no error while setting the property
        // call all handlers
        target[handlers].forEach(handler => handler(property, value));
      }
      return success;
    }
  });
}

let user = {};

user = makeObservable(user);

user.observe((key, value) => {
  alert(`SET ${key}=${value}`);
});

user.name = "John";