简体   繁体   中英

JavaScript Proxy Setter doesn't make a second Proxy call

I have the following code that is using Proxy for Class setter. In my example I am tracking specific variable to update some other variables. My Setter is writing a log of all changes to Console. However if I try to modify a variable from a setter itself, variable gas modified, but the Proxy isn't called. Is it by design to avoid looping? Or am I missing something?

 class darthVader { constructor() { return new Proxy(this, { set(obj, prop, value) { console.log(`Setting ${prop} to ${value}`) obj[prop] = value return true } }) } set resistance(val) { this._resistance= val this.darkSide = false } get resistance() { return this._R2D2 } } let newHero = new darthVader() newHero.resistance = 11 console.log(newHero.darkSide)

The problem is that your trap just runs obj[prop] = value , which sets a property on the target obj not on the proxy. What you should do instead is to use the Reflect.set method that provides the default implementation for the set trap, and expects an optional receiver argument. This receiver is the object that setters will be evaluated against, and you should pass the receiver argument of the set trap (which will refer to the newHero proxy that you assigned resistance to).

 class DarthVader { set resistance(val) { this._resistance= val this.darkSide = false } get resistance() { return this._R2D2 } } let newHero = new Proxy(new DarthVader, { set(target, prop, value, receiver) { console.log(`Setting ${prop} to ${value}`) return Reflect.set(target, prop, value, receiver) // ^^^^^^^^^^^ // obj[prop] = value } }); newHero.resistance = 11 console.log(newHero.darkSide)

The obj inside the set method refers to what this is when you do return new Proxy(this , and that object is not a proxy, but the darthVader instance itself - the one that's in the process of being created by the darthVader constructor. So, when you assign to a property of obj , you're putting a property directly on the darthVader instance, rather than on the proxy instance (which is the newHero ). So, the proxy method doesn't get called.

If you wanted to recursively invoke the proxy, you could define it (let's say, as the variable name proxy ) before returning it from the constructor, and then reference proxy inside the set method, but given the current logic, this results in a stack overflow because you'd be continually calling the proxy's setter:

 class darthVader { constructor() { const proxy = new Proxy(this, { set(obj, prop, value) { console.log(`Setting ${prop} to ${value}`) proxy[prop] = value return true } }) return proxy; } set resistance(val) { this._resistance = val this.darkSide = false } get resistance() { return this._R2D2 } } let newHero = new darthVader() newHero.resistance = 11 console.log(newHero.darkSide)

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