How to create a Deep Proxy?

前端 未结 1 1518
日久生厌
日久生厌 2021-02-15 03:23

How can I create a deep/recursive Proxy?

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

Here\'s what I\'ve got

1条回答
  •  攒了一身酷
    2021-02-15 04:17

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

    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.

    0 讨论(0)
提交回复
热议问题