【问题标题】:JavaScript Proxy Setter doesn't make a second Proxy callJavaScript Proxy Setter 不进行第二次代理调用
【发布时间】:2019-12-23 09:29:43
【问题描述】:
我有以下代码使用类设置器的代理。在我的示例中,我正在跟踪特定变量以更新其他一些变量。我的 Setter 正在将所有更改的日志写入控制台。但是,如果我尝试从 setter 本身修改变量,则变量 gas 已修改,但不会调用代理。是为了避免循环而设计的吗?还是我错过了什么?
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)
【问题讨论】:
标签:
javascript
ecmascript-6
proxy
【解决方案1】:
问题是您的陷阱只是运行obj[prop] = value,它在目标obj 上设置了一个属性,而不是在代理上。你应该做的是使用Reflect.set method,它为设置陷阱提供默认实现,并期望一个可选的receiver 参数。此接收器是设置器将对其进行评估的对象,您应该传递receiver argument of the set trap(它将引用您分配给resistance 的newHero 代理)。
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)
【解决方案2】:
set 方法中的obj 指的是当您执行return new Proxy(this 时的this,并且该对象不是 代理,而是darthVader 实例本身 - darthVader 构造函数正在创建的那个。因此,当您分配给obj 的属性时,您将属性直接放在darthVader 实例上,而不是放在代理实例(即newHero)上。因此,不会调用代理方法。
如果你想递归调用代理,你可以在从构造函数返回它之前定义它(比如说,作为变量名proxy),然后在set方法中引用proxy,但是给出当前逻辑,这会导致堆栈溢出,因为您会不断调用代理的设置器:
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)