如何创建Deep Proxy? [英] How to create a Deep Proxy?

查看:94
本文介绍了如何创建Deep Proxy?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何创建深度/递归代理

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

Specifically, I want to know whenever a property is set or modified anywhere in the object tree.

以下是我到目前为止的内容:

Here's what I've got so far:

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 触发了setter,即使我'已从代理的对象树中删除它。删除该属性后,有没有办法去除 baz

As you can see, I've just about got it working, except baz.quux.duck = 666 is triggering the setter even though I've removed it from proxy's object tree. Is there any way to de-proxify baz after the property has been deleted?

推荐答案

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

Fixed a bunch of bugs in my original question. I think this works now:

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, []);
}


module.exports = createDeepProxy;

用法:

let proxied = createDeepProxy(obj, {
    set(target, path, value, receiver) {
        console.log(Chalk.green('set'), path.join('.'), Chalk.dim('='), inspect(value));
    },

    deleteProperty(target, path) {
        console.log(Chalk.red('delete'), path.join('.'));
    }
});

proxied.foo = 'bar'; // will trigger `set`
delete proxified.foo; // will trigger `deleteProperty`

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

You can assign full objects to properties and they'll get recursively proxified, and then when you delete them out of the proxied object they'll get deproxied so that you don't get notifications for objects that are no longer part of the object-graph.

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

I have no idea what'll happen if you create a circular linking. I don't recommend it.

这篇关于如何创建Deep Proxy?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆