0

Say I have an object, var obj = {}. I want to have a handler invoked when at a later time, any field is retrieved; obj.b.

I am aware of proxies,

var obj = {};
var proxy = new Proxy(obj, {
  get(obj, prop) {
    console.log('get', prop)
    return Reflect.get(obj, prop);
  }
})

However, this will only log when accessing properties through the proxy proxy.b and will fail to log otherwise obj.b.

I am also aware of using defineProperty to put getters on all the keys of obj. However, this won't handle new fields that are added to obj after the getters were added.

Maybe if it's possible to re-implement proxy, then it should be possible to add the handlers to the original obj instead of the proxy. I've tried investigating the proxy object, but it seems to be implemented internally. new Proxy({},{}) has properties [[Handler]], [[Target]], and [[IsRevoked]], but I was not able to access or view these objects; proxy['[[Handler]]'] returns undefined. I was thinking if I could just add those handler and target fields to obj myself, instead of creating a separate proxy object, then I could make obj act like a proxy.

I have read through MDN's docs for proxies, defineProperty, and handlers and even http://exploringjs.com/es6/ch_proxies.html. I've likewise come across multiple stack overflow posts achieving something similar but not quite complete.

--- edit, my use case (in case this has a clearer solution than the solution I was aiming for) ---

I'm binding a source object to dom elmenets. E.g., you change source.text, and some text on the dom changes as well. To do this, source is a proxy, with a set handler to update the dom appropriately. However, to allow nested fields on source, I have to also be handling when source.obj.text changes. To do so, I the source proxy has a get hander as well, which also returns a proxy with similar set and get handlers. Code snippet below:

let createProxy = (obj, handlers) => new Proxy(obj, {
    get: (target, prop) => {
        let got = Reflect.get(target, prop);
        return typeof got === 'object' && got !== null ? createProxy(got, handlers && handlers[prop]) : got;
    },
    set: (target, prop, value) => {
        if (Reflect.get(target, prop) !== value) {
            Reflect.set(target, prop, value);

            handlers && propogateHandlerDown(handlers);
        }
        return true;
    }
});

This is used internally by let source = createProxy({}, ...), and then the source is returned the user. This works fine usually. The problem arises, when the user does not use source, e.g.

let obj = {};
source.list = [obj];
source.list[0].text = 'this works fine';
obj.text = 'this does not work, as obj is not a proxy';
junvar
  • 11,151
  • 2
  • 30
  • 46
  • I don’t think what you want exists. – Mark Apr 12 '18 at 14:42
  • A `Proxy` can't be polyfilled with a JavaScript implementation. But why can't you return the `proxy` instead of the `obj`? The whole point of the proxy is that calling code uses its handle instead of the original object created, so that reflection can be intercepted. – Patrick Roberts Apr 12 '18 at 14:48
  • 1
    By the way, any time you see `[[SomePropertyName]]` in the debugger, those are references to things in the ECMAScript specification, implementation details, etc., and cannot be programmatically accessed in JavaScript. – Patrick Roberts Apr 12 '18 at 14:51
  • @PatrickRoberts, my specific use case is a bit wordy, but I do return a proxy, but can't guarantee the user will use the proxy. I'll add it to the bottom of my question, in case anyone has a solution for my use case rather than this broader question. – junvar Apr 12 '18 at 15:38
  • It's impossible to watch an object with the same capability as a `Proxy` without creating a `proxy` reference through which to access the original object. – Patrick Roberts Apr 12 '18 at 15:43
  • I was thinking, maybe we can create some kind of catch all getter (via defineProperty) on all of the fields of the original object. Maybe then dynamically add more getters as the root object has fields created by having a onFieldCreatedHandler on the root object, but I don't know if that's possible? – junvar Apr 12 '18 at 15:48

0 Answers0