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