2

I am using Object.defineProperty to override getter and setter on an object, so that I can listen to all the mutation events.

var a = {};
Object.defineProperty(a, key, {
  get: function(){
    ..
  },
  set: function(val){
    ..
  }
}

This works fine, but there's one caveat--I need to know in advance what attributes I want to listen to--which means I need to iterate through all the keys I want to watch in the beginning.

If I wanted to randomly assign a new attribute during runtime like this:

a.new_attr=1;

it wouldn't work because I haven't defined the new_attr property yet.

Is there a way to either:

  1. dynamically run Object.defineProperty() when I assign the attribute for the first time; or
  2. any other way to handle situations like this? (Maybe some way to monitor ALL attributes without specifying the keys)
Vlad
  • 8,038
  • 14
  • 60
  • 92

1 Answers1

3

I think what you really want to use is a Proxy. Proxies allow you to intercept events such as get and set.

var obj = {
  a: 1,
  b: 2
};
var proxiedObj = new Proxy(obj, {
  get: function(target, name) {
    console.log(`get: ${name}`);
    return target[name];
  },
  set: function(target, prop, value) {
    console.log(`set: ${prop}`);
    target[prop] = value;
  }
});

console.log(proxiedObj.a);
console.log(proxiedObj.b);

// Notice that it still works even on new properties
proxiedObj.c = 3;
console.log(proxiedObj.c);
Mike Cluck
  • 31,869
  • 13
  • 80
  • 91
  • 1
    Note: This only works in ES2015/ES6+ environments and _cannot_ be transpiled. – nils Apr 24 '17 at 14:05
  • @nils Very good point. Technically, it *can* be transpiled ([sort of](http://stackoverflow.com/questions/35025204/javascript-proxy-support-in-babel/35025383#35025383)) but is incredibly slow. – Mike Cluck Apr 24 '17 at 14:09
  • Oh wow, I hadn't seen that solution before. Very creative, but not suitable for production. – nils Apr 24 '17 at 14:24
  • Thanks for the answer, unfortunately i'm looking for a classic JS solution. So would this mean there's no solution that works for ordinary JS that will work out of the box in all browsers? I am trying hard not to use the new versions of ES because I want to keep it simple. – Vlad Apr 24 '17 at 14:28
  • @Vlad There's no solution that will work with ES5. Proxies were made specifically to handle situations like these. There's no comparable mechanism in ES5. As you stated, you can make it work if all of the keys are known before hand but you have no way of hooking in to new keys. – Mike Cluck Apr 24 '17 at 14:31