如this SO question所示,Proxy
个对象是观察对象变化的好方法。
如果您想观看子对象的更改,该怎么办?您还需要代理这些子对象。
我正在使用一些自动执行此操作的代码 - 只要您尝试设置属性,就会确保它包含在代理中。我们这样做是为了让我们可以在每次任何值变化时执行操作。
function createProxiedObject(objToProxy) {
return new Proxy(objToProxy, {
set: function (target, key, value) {
//proxy nested objects
if (value !== null && typeof value === 'object') {
value = createProxiedObject(value);
}
target[key.toString()] = value;
handleProxiedObjectChange();
});
这很有效,但至少有一种情况可以解决这个问题:
function ensureObjectHasProperty(object, key, default) {
if (object[key] !== null) {
// some validation happens here
return object[key];
} else {
return default;
}
}
...
proxiedObject = somethingThatCreatesAProxiedObject(someValue);
proxiedObject[someProperty] = ensureObjectHasProperty(proxiedObject, someProperty, defaultValue)
结果是someProperty
(已经被代理)下的值被重新分配给代理对象,导致它被包装在另一个代理中。这导致每次对象的任何部分发生更改时都会多次调用handleProxiedObjectChange
方法。
解决这个问题的简单方法是永远不要向代理对象分配任何东西,除非它是新的,但是由于这个问题已经发生,所以将来有人会再次这样做。如何修复set
函数以不重新包装已经被代理的对象?或者是否有更好的方法来观察对象,以便在对象或其任何子对象发生更改时可以调用handleProxiedObjectChange
?
答案 0 :(得分:1)
正如@DecentDabbler所建议的,使用WeakSet
允许我确保我从不尝试将代理包装在另一个代理中:
const proxiedObjs = new WeakSet();
...
function createProxiedObject(objToProxy) {
// Recursively ensure object is deeply proxied
for (let x in objToProxy) {
subObj = objToProxy[x];
if (subObj !== null && typeof subObj === 'object' && !proxiedObjs.has(subObj)) {
objToProxy[x] = createProxiedObject(subObj);
}
}
let proxied = new Proxy(objToProxy, {
set: function (target, key, value) {
//This check is also new - if nothing actually changes
//I'd rather not call handleProxiedObjectChange
if (_.isEqual(target[key.toString()], value)) {
return true;
}
//proxy nested objects
if (value !== null && typeof value === 'object' && !proxiedObjs.has(value)) {
value = createProxiedObject(value);
}
target[key.toString()] = value;
handleProxiedObjectChange();
});
proxiedObjs.add(proxied);
return proxied;