mpe*_*pen 8 javascript proxy node.js ecmascript-6
如何创建深度/递归代理?
具体来说,我想知道在对象树中的任何位置设置或修改属性.
这是我到目前为止所得到的:
function deepProxy(obj) {
return new Proxy(obj, {
set(target, property, value, receiver) {
console.log('set', property,'=', value);
if(typeof value === 'object') {
for(let k of Object.keys(value)) {
if(typeof value[k] === 'object') {
value[k] = deepProxy(value[k]);
}
}
value = deepProxy(value);
}
target[property] = value;
return true;
},
deleteProperty(target, property) {
if(Reflect.has(target, property)) {
let deleted = Reflect.deleteProperty(target, property);
if(deleted) {
console.log('delete', property);
}
return deleted;
}
return false;
}
});
}
Run Code Online (Sandbox Code Playgroud)
这是我的测试:
const proxy = deepProxy({});
const baz = {baz: 9, quux: {duck: 6}};
proxy.foo = 5;
proxy.bar = baz;
proxy.bar.baz = 10;
proxy.bar.quux.duck = 999;
baz.quux.duck = 777;
delete proxy.bar;
delete proxy.bar; // should not trigger notifcation -- property was already deleted
baz.quux.duck = 666; // should not trigger notification -- 'bar' was detached
console.log(proxy);
Run Code Online (Sandbox Code Playgroud)
并输出:
set foo = 5
set bar = { baz: 9, quux: { duck: 6 } }
set baz = 10
set duck = 999
set duck = 777
delete bar
set duck = 666
{ foo: 5 }
Run Code Online (Sandbox Code Playgroud)
正如你所看到的,我只是让它工作,除了baz.quux.duck = 666触发setter,即使我已经从proxy对象树中删除它.baz删除该属性后,有什么方法可以解除代理吗?
这是一个更简单的方法,可以实现我认为您想要的功能。
此示例允许您深入获取或设置任何属性,并调用任何属性(深入或不深入)的更改处理程序以显示其有效:
let proxyCache = new WeakMap();
function createDeepOnChangeProxy(target, onChange) {
return new Proxy(target, {
get(target, property) {
const item = target[property];
if (item && typeof item === 'object') {
if (proxyCache.has(item)) return proxyCache.get(item);
const proxy = createDeepOnChangeProxy(item, onChange);
proxyCache.set(item, proxy);
return proxy;
}
return item;
},
set(target, property, newValue) {
target[property] = newValue;
onChange();
return true;
},
});
}
let changeCount = 0
const o = createDeepOnChangeProxy({}, () => changeCount++)
o.foo = 1
o.bar = 2
o.baz = {}
o.baz.lorem = true
o.baz.yeee = {}
o.baz.yeee.wooo = 12
o.baz.yeee === o.baz.yeee // proxyCache ensures that this is true
console.log(changeCount === 6)
const proxy = createDeepOnChangeProxy({}, () => console.log('change'))
const baz = {baz: 9, quux: {duck: 6}};
proxy.foo = 5;
proxy.bar = baz;
proxy.bar.baz = 10;
proxy.bar.quux.duck = 999;
baz.quux.duck = 777;
delete proxy.bar;
delete proxy.bar; // should not trigger notifcation -- property was already deleted
baz.quux.duck = 666; // should not trigger notification -- 'bar' was detached
console.log(proxy);
Run Code Online (Sandbox Code Playgroud)
在使用您的代码示例的部分中,没有像您想要的评论那样的额外通知。
修复了原始问题中的一堆错误.我认为现在有效:
function createDeepProxy(target, handler) {
const preproxy = new WeakMap();
function makeHandler(path) {
return {
set(target, key, value, receiver) {
if (typeof value === 'object') {
value = proxify(value, [...path, key]);
}
target[key] = value;
if (handler.set) {
handler.set(target, [...path, key], value, receiver);
}
return true;
},
deleteProperty(target, key) {
if (Reflect.has(target, key)) {
unproxy(target, key);
let deleted = Reflect.deleteProperty(target, key);
if (deleted && handler.deleteProperty) {
handler.deleteProperty(target, [...path, key]);
}
return deleted;
}
return false;
}
}
}
function unproxy(obj, key) {
if (preproxy.has(obj[key])) {
// console.log('unproxy',key);
obj[key] = preproxy.get(obj[key]);
preproxy.delete(obj[key]);
}
for (let k of Object.keys(obj[key])) {
if (typeof obj[key][k] === 'object') {
unproxy(obj[key], k);
}
}
}
function proxify(obj, path) {
for (let key of Object.keys(obj)) {
if (typeof obj[key] === 'object') {
obj[key] = proxify(obj[key], [...path, key]);
}
}
let p = new Proxy(obj, makeHandler(path));
preproxy.set(p, obj);
return p;
}
return proxify(target, []);
}
let obj = {
foo: 'baz',
}
let proxied = createDeepProxy(obj, {
set(target, path, value, receiver) {
console.log('set', path.join('.'), '=', JSON.stringify(value));
},
deleteProperty(target, path) {
console.log('delete', path.join('.'));
}
});
proxied.foo = 'bar';
proxied.deep = {}
proxied.deep.blue = 'sea';
delete proxied.foo;
delete proxied.deep; // triggers delete on 'deep' but not 'deep.blue'Run Code Online (Sandbox Code Playgroud)
用法:
function createDeepProxy(target, handler) {
const preproxy = new WeakMap();
function makeHandler(path) {
return {
set(target, key, value, receiver) {
if (typeof value === 'object') {
value = proxify(value, [...path, key]);
}
target[key] = value;
if (handler.set) {
handler.set(target, [...path, key], value, receiver);
}
return true;
},
deleteProperty(target, key) {
if (Reflect.has(target, key)) {
unproxy(target, key);
let deleted = Reflect.deleteProperty(target, key);
if (deleted && handler.deleteProperty) {
handler.deleteProperty(target, [...path, key]);
}
return deleted;
}
return false;
}
}
}
function unproxy(obj, key) {
if (preproxy.has(obj[key])) {
// console.log('unproxy',key);
obj[key] = preproxy.get(obj[key]);
preproxy.delete(obj[key]);
}
for (let k of Object.keys(obj[key])) {
if (typeof obj[key][k] === 'object') {
unproxy(obj[key], k);
}
}
}
function proxify(obj, path) {
for (let key of Object.keys(obj)) {
if (typeof obj[key] === 'object') {
obj[key] = proxify(obj[key], [...path, key]);
}
}
let p = new Proxy(obj, makeHandler(path));
preproxy.set(p, obj);
return p;
}
return proxify(target, []);
}
let obj = {
foo: 'baz',
}
let proxied = createDeepProxy(obj, {
set(target, path, value, receiver) {
console.log('set', path.join('.'), '=', JSON.stringify(value));
},
deleteProperty(target, path) {
console.log('delete', path.join('.'));
}
});
proxied.foo = 'bar';
proxied.deep = {}
proxied.deep.blue = 'sea';
delete proxied.foo;
delete proxied.deep; // triggers delete on 'deep' but not 'deep.blue'Run Code Online (Sandbox Code Playgroud)
您可以将完整对象分配给属性,它们将以递归方式进行代理,然后当您从代理对象中删除它们时,它们将被取消,这样您就不会收到不再属于对象的对象的通知 - 图形.
我不知道如果你创建一个循环链接会发生什么.我不推荐它.
| 归档时间: |
|
| 查看次数: |
1810 次 |
| 最近记录: |