最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

mutation - Transform a Javascript object into a proxy (and not its reference) - Stack Overflow

programmeradmin0浏览0评论

I can take a Javascript object o and create a new Proxy object from it:

let p = new Proxy(object, { ... })

But is there a way to mutate an existing object reference to track changes on the original object? In particular, is there a way I can track the addition of new keys on the object from exterior sources?

I can take a Javascript object o and create a new Proxy object from it:

let p = new Proxy(object, { ... })

But is there a way to mutate an existing object reference to track changes on the original object? In particular, is there a way I can track the addition of new keys on the object from exterior sources?

Share Improve this question edited Jun 3, 2023 at 17:06 dumbass 27.3k4 gold badges37 silver badges73 bronze badges asked Aug 27, 2018 at 1:41 yawnyawn 5161 gold badge7 silver badges26 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 6

The Proxy spec supports defining a proxy on the prototype of an object as a means for inspecting actions on that object when they do not exist on the instance. While this isn't full parity with .watch() it does allow for your mentioned use case of knowing when new properties are added. Here is an example, with ments about caveats...

  // 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

Just create the object first and keep a reference to it before creating its Proxy.

Now you can modify either of them (the original object or its Proxy) and the other will also receive the changes unless you prevent them on the Proxy:

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

If you want to be notified when a new property is added, deleted or modified on an object without the possiblity that the original reference is used to mutate the original object directly, the only option you have is to create that object directly as a Proxy or overwrite the original one:

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

There used to be an Object.prototype.watch(), but it has been deprecated.

发布评论

评论列表(0)

  1. 暂无评论