我可以获取一个Javascript对象o
并从中创建一个新的Proxy对象:
let p = new Proxy(object, { ... })
但是有一种方法可以改变现有对象的引用以跟踪原始对象的变化?特别是,有什么方法可以跟踪外部源在对象上添加的新键吗?
答案 0 :(得分:2)
只需先创建对象,并在创建其代理之前对其进行引用即可。
现在,您可以修改其中任何一个(原始对象或其代理),并且除非您在代理上阻止它们,否则另一个也将收到更改:
const o = {};
const p = new Proxy(o, {
set: function(obj, prop, value) {
if (prop === 'd') {
return false;
}
obj[prop] = value;
return true;
},
});
// These operations are forwarded to the target object o:
p.a = 0;
p.b = 1;
// This one is prevented by the Proxy:
p.d = true;
// Both will have two properties, a and b:
console.log(o);
// You can also mutate the original object o and the Proxy will also get those changes:
o.c = false;
// Note that now the Proxy setter is not called, so you can do:
o.d = true;
// But the Proxy still gets the change:
console.log(p);
如果要在对象上添加,删除或修改新属性时收到通知,而又没有使用原始引用直接使原始对象发生变异的可能性,那么唯一的选择就是直接创建该对象为代理或覆盖原始代理:
// Created from an empty object without a reference to it:
// const p = new Proxy({}, { ... });
// Overwrite the original reference:
let myObject = { a: 1, b: 2 };
myObject = new Proxy(myObject, {
set: function(obj, prop, value) {
if (prop in obj) {
console.log(`Property ${ prop } updated: ${ value }`);
} else {
console.log(`Property ${ prop } created: ${ value }`);
}
obj[prop] = value;
return true;
},
deleteProperty(obj, prop) {
console.log(`Property ${ prop } deleted`);
delete obj[prop];
}
});
// Now there's no way to access the original object we
// passed in as the Proxy's target!
myObject.a = true;
myObject.a = false;
delete myObject.a;
曾经有一个Object.prototype.watch()
,但已经过时了。
答案 1 :(得分:1)
代理规范支持在对象的原型上定义代理,以作为检查实例上不存在对该对象的操作的一种手段。尽管这与.watch()
并不完全相同,但确实允许您提到的用例知道何时添加新属性。这是一个示例,其中包含有关警告的评论...
// assuming some existing property you didn't create...
const t = { existing: true };
// proxy a new prototype for that object...
const ctr = {};
Object.setPrototypeOf(t, new Proxy(ctr, {
get(target, key) {
console.log('icu get');
return Reflect.get(target, key) || ctr[key];
},
set(target, key, val) {
console.log('icu set');
// setting this container object instead of t keeps t clean,
// and allows get access to that property to continue being
// intercepted by the proxy
Reflect.set(ctr, key, val);
return true;
},
deleteProperty(target, key) {
console.log('icu delete');
delete ctr[key];
return true;
}
}));
// existing properties don't work
console.log('existing');
t.existing; // <nothing>
t.existing = false; // <nothing>
// new properties work
console.log('new');
t.test; // icu get
t.test = 4; // icu set
console.log(t.test); // icu get
// 4
// but this doesn't work (and I think it should be a bug)
console.log('delete');
delete t.test; // icu get
// <missing icu delete>
console.log(t.test); // 4