torna alle lezioni

Observable

Create una funzione makeObservable(target) che “rende l’oggetto osservabile” ritornandone un proxy.

Ecco come dovrebbe funzionare:

function makeObservable(target) {
  /* il vostro codice */
}

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

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

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

In altre parole, un oggetto ritornato da makeObservable equivale a quello originale, ma possiede il metodo observe(handler) che imposta la funzione handler per essere invocata quando una qualsiasi proprietà cambia.

Quando una proprietà verrà modificata, handler(key, value) verrà invocato con il nome ed il valore della proprietà.

P.S. In questo task, gestite solamente la scrittura della proprietà. Le altre operazioni possono essere implementate in maniera simile.

La soluzione consiste di due parti:

  1. Quando .observe(handler) viene invocato, dobbiamo memorizzare l’handler da qualche parte, per poter essere in grado di invocarlo più tardi. Possiamo memorizzare gli handler nell’oggetto, utilizzando un symbol come chiave della proprietà.
  2. Abbiamo bisogno di un proxy con la trappola set per poter invocare gli handlers in caso di cambiamenti.
let handlers = Symbol('handlers');

function makeObservable(target) {
  // 1. Inizializziamo lo store per gli handlers
  target[handlers] = [];

  // Memorizziamo l'handler nell'array per poterlo invocare successivamente
  target.observe = function(handler) {
    this[handlers].push(handler);
  };

  // 2. Creiamo un proxy per gestire le modifiche
  return new Proxy(target, {
    set(target, property, value, receiver) {
      let success = Reflect.set(...arguments); // inoltriamo l'operazione all'oggetto
      if (success) { // se non è stato generato alcun errore durante il cambiamento della proprietà
        // invochiamo tutti gli 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";