简体   繁体   中英

Proxy object - access target from within a getter property?

I have a simple proxy object:

 const myProxy = new Proxy( /* myTarget */ { test: 2, }, /* myHandler */ { get(target, prop, proxy) { if (prop in this && this[prop] instanceof Function) return this[prop](target); //getter return target[prop]; //value }, myGetter(target) { return ++target.test } } ); console.log("test before", myProxy.test); console.log("myGetter", myProxy.myGetter); console.log("test after", myProxy.test);

Is there a way make myGetter property as a true getter? My attempt failed, because I don't know how to access myTarget from within the getter:

 const myProxy = new Proxy( /* myTarget */ { test: 2, }, /* myHandler */ { get(target, prop, proxy) { if (prop in this) return this[prop]; //getter return target[prop]; //value }, get myGetter() { return ++target.test; //target undefined } } ); console.log("test before", myProxy.test); console.log("blah", myProxy.myGetter); console.log("test after", myProxy.test);

The reason why I need this is because I have multiple functions inside the handler and I need to determine which one needs to be executed within handler itself ( myGetter ), or should be returned as function reference ( myFunc ), where it can also accept additional data as arguments, so I'm using prop instanceof Function to check if it's a function or not:

 const myProxy = new Proxy( /* myTarget */ { test: 2, }, /* myHandler */ { get(target, prop, proxy) { if (prop in this) { if (this[prop] instanceof Function) return (args) => this[prop](target, args); //function return this[prop]; //getter } return target[prop]; //value }, get myGetter() { return ++target.test; //target undefined }, myFunc(target, value) { return target.test * value; } } ); console.log("myFunc", myProxy.myFunc(3)); console.log("test before", myProxy.test); console.log("myGetter", myProxy.myGetter); console.log("test after", myProxy.test);

I could think of several work arounds, for example hard code names of functions:

 const myProxy = new Proxy( /* myTarget */ { test: 2, }, /* myHandler */ { get(target, prop, proxy) { if (prop in this) { if (["myFunc"].includes(prop)) // function return (args) => this[prop](target, args); return this[prop](target); // getter } return target[prop]; }, myGetter(target) { return ++target.test }, myFunc(target, value) { return target.test * value; } } ); console.log("myFunc", myProxy.myFunc(3)); console.log("test before", myProxy.test); console.log("myGetter", myProxy.myGetter); console.log("test after", myProxy.test);

Or separate functions into groups:

 const myProxy = new Proxy( /* myTarget */ { test: 2, }, /* myHandler */ { get(target, prop, proxy) { if (prop in this._myFuncs) return (args) => this._myFuncs[prop](target, args); if (prop in this._myGetters) return this._myGetters[prop](target); return target[prop]; }, _myGetters: { myGetter(target) { return ++target.test }, }, _myFuncs: { myFunc(target, value) { return target.test * value; }, } } ); console.log("myFunc", myProxy.myFunc(3)); console.log("test before", myProxy.test); console.log("myGetter", myProxy.myGetter); console.log("test after", myProxy.test);

For education purpose any suggestions how to make true getter to work in Proxy?

I don't think the handler object should have nonstandard properties on it - it'd make more sense for it to only have the traps that it's expected to have . To have collection of properties for traps, either hard-code those properties (which is inflexible and not so nice) or use a separate object structure for those properties. With a separate object in the proxy closure, checking whether the property exists on the object and then .call ing it with target if it's a getter is easy.

 const makeProxy = (target, customProperties) => { return new Proxy( target, { get(target, prop, proxy) { if (prop in customProperties) { // Invoke getter if it exists on customProperties const { get } = Object.getOwnPropertyDescriptor(customProperties, prop); if (get) { return get.call(target); } } // Otherwise return original object value or getter return target[prop]; }, } ); }; const proxy = makeProxy({ test: 2, }, { get myGetter() { return ++this.test } }); console.log("test before", proxy.test); console.log("blah", proxy.myGetter); console.log("test after", proxy.test);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM