可观察的(Observable)
创建一个函数 makeObservable(target)
,该函数通过返回一个代理“使得对象可观察”。
其工作方式如下:
function makeObservable(target) {
/* 你的代码 */
}
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)
函数。
P.S. 在本任务中,你可以只关注属性写入。其他的操作可以通过类似的方式实现。
该解决方案包括两部分:
- 无论
.observe(handler)
何时被调用,我们都需要在某个地方记住 handler,以便以后可以调用它。我们可以使用 Symbol 作为属性键,将 handler 直接存储在对象中。 - 我们需要一个带有
set
陷阱的 proxy 来在发生任何更改时调用 handler。
let handlers = Symbol('handlers');
function makeObservable(target) {
// 1. 初始化 handler 存储
target[handlers] = [];
// 将 handler 函数存储到数组中,以便于之后调用
target.observe = function(handler) {
this[handlers].push(handler);
};
// 2. 创建一个 proxy 以处理更改
return new Proxy(target, {
set(target, property, value, receiver) {
let success = Reflect.set(...arguments); // 将操作转发给对象
if (success) { // 如果在设置属性时没有出现 error
// 调用所有 handler
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";