返回課程

可觀察物件

建立一個函式 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 傳回的物件就像原始物件一樣,但它還有一個方法 observe(handler),這個方法會設定 handler 函式,以便在任何屬性變更時呼叫它。

每當屬性變更時,handler(key, value) 就會使用屬性的名稱和值來呼叫。

附註:在此任務中,請僅注意寫入屬性。其他操作可以以類似的方式實作。

此解決方案包含兩個部分

  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";