Observable
Создайте функцию makeObservable(target)
, которая делает объект «наблюдаемым», возвращая прокси.
Вот как это должно работать:
function makeObservable(target) {
/* ваш код */
}
let user = {};
user = makeObservable(user);
user.observe((key, value) => {
alert(`SET ${key}=${value}`);
});
user.name = "John"; // выводит: SET name=John
Другими словами, возвращаемый makeObservable
объект аналогичен исходному, но также имеет метод observe(handler)
, который позволяет запускать handler
при любом изменении свойств.
При изменении любого свойства вызывается handler(key, value)
с именем и значением свойства.
P.S. В этой задаче ограничьтесь, пожалуйста, только записью свойства. Остальные операции могут быть реализованы похожим образом.
Решение состоит из двух частей:
- При вызове
.observe(handler)
нам нужно где-то сохранить обработчик, чтобы вызвать его позже. Можно хранить обработчики прямо в объекте, создав в нём для этого свой символьный ключ. - Нам нужен прокси с ловушкой
set
, чтобы вызывать обработчики при изменении свойств.
let handlers = Symbol('handlers');
function makeObservable(target) {
// 1. Создадим хранилище обработчиков
target[handlers] = [];
// положим туда функции-обработчики для вызовов в будущем
target.observe = function(handler) {
this[handlers].push(handler);
};
// 2. Создадим прокси для реакции на изменения
return new Proxy(target, {
set(target, property, value, receiver) {
let success = Reflect.set(...arguments); // перенаправим операцию к оригинальному объекту
if (success) { // если не произошло ошибки при записи свойства
// вызовем обработчики
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";