gpt4 book ai didi

javascript - 如何创建深度代理(又名代理膜)?

转载 作者:数据小太阳 更新时间:2023-10-29 04:14:28 26 4
gpt4 key购买 nike

如何创建深度/递归 Proxy

具体来说,我想知道何时在对象树中的任何位置设置或修改属性。

这是我到目前为止所得到的:

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;
}
});
}

这是我的测试:

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);

输出:

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 }

如您所见,除了 baz.quux.duck = 666 之外,我几乎已经开始工作了即使我已将其从 proxy 中删除,也会触发 setter 的对象树。有什么方法可以解除代理 baz在属性被删除之后?

最佳答案

修复了我原来问题中的一堆错误。我认为这现在有效:

function createDeepProxy(target, handler) {
const preproxy = new WeakMap();

function makeHandler(path) {
return {
set(target, key, value, receiver) {
if (value != null && 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 (obj[key][k] != null && typeof obj[key][k] === 'object') {
unproxy(obj[key], k);
}
}

}

function proxify(obj, path) {
for (let key of Object.keys(obj)) {
if (obj[key] != null && 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';
proxied.null = null;
delete proxied.foo;
delete proxied.deep; // triggers delete on 'deep' but not 'deep.blue'

您可以将完整的对象分配给属性,它们将被递归代理,然后当您将它们从代理对象中删除时,它们将被解除代理,这样您就不会收到不再属于的对象的通知对象图。

我不知道如果您创建循环链接会发生什么。我不推荐它。

关于javascript - 如何创建深度代理(又名代理膜)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43177855/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com