ES6 代理:set() 陷阱不触发,在目标对象的方法内部设置时
ES6 Proxy: set() trap not triggering, when setting inside target object's method
示例:
let foo = {bar: 'baz', method() { this.bar = 'baz2' }}
let fooProxy = new Proxy(foo, {set(target, key, val) { console.log('set trap triggered!') }})
fooProxy.bar = 'any value' // as expected: set trap triggered!
foo.method() // trap not triggered
为什么会这样?如何在目标对象内部执行触发陷阱?
编辑,主要是为了给@Bergi解释一下:
我的主要目标是拦截对 foo 对象的任何更改,因此我可以设置 属性 例如foo.changed 为真。另外,我想拦截对 array/object 类型的 foo 属性的更改。你知道,如果我设置 foo 的 属性,一切正常,但是当我例如推送到一个数组,然后代理无法拦截它。所以我也需要将 array/object 属性转换为代理(我称它们为 ArrayProxy 和 ObjectProxy)。
这是我的代码(打字稿):
// Category.ts
class Category extends Model {
title: string = ''
products: Product[] = []
}
// Model.ts
abstract class Model extends BaseModel {
constructor() {
return new Proxy(this, {
set (target, key, val) {
if (Array.isArray(val) {
target[key] = new ArrayProxy(val) // I WANT all array properties to be ArrayProxy but the problem (see below) not let me do that
}
}
})
}
}
// BaseModel.ts
abstract class BaseModel {
constructor(attributes) {
this.setAttributes(attributes)
}
setAttributes(attributes) {
Object.keys(attributes).forEach((key) => {
this[key] = attributes[key] // THE PROBLEM
})
}
}
我已经删除了代码,这无关紧要(例如,对象属性和 ObjectProxy 的类似情况)。
如果有更优雅的方法来完成我所做的,我将不胜感激。
在 foo.method
中,您没有通过代理对象设置 属性,因此显然不会触发任何陷阱。代理不修改原始对象。
原始对象上不存在陷阱。如果可以,您将不需要单独的代理对象。思路是用代理代替原来的。
一种可能是让您的原始对象继承自代理对象。这可能有效,具体取决于您实际需要完成的任务。
let fooProxy = new Proxy({}, {
set(target, key, val) { console.log('set trap triggered!') }
})
let foo = Object.create(fooProxy, {
method: {value: function() { this.bar = 'baz2' }}
})
fooProxy.bar = 'any value'
foo.method()
未触发设置陷阱,因为您在 method()
中访问的 this
不是代理而是原始对象 foo
。代理不会更改原始对象。您可以通过检查 this
里面的内容来查看 method()
:
let foo = {
method () {
return this === fooProxy
}
}
let fooProxy = new Proxy(foo, {})
document.write(foo.method()) //=> false
您可以使用 Function#call
:
在调用时显式设置 method()
的上下文
let foo = {bar: 'baz', method() { this.bar = 'baz2' }}
let fooProxy = new Proxy(foo, {set(target, key, val) { console.log('set trap triggered!') }})
fooProxy.bar = 'any value' //=> set trap triggered!
foo.method.call(fooProxy) //=> set trap triggered!
您还可以将代理添加到对象原型中。
SomeObject.prototype = new Proxy(
SomeObject.prototype,
SomeObjectHandlerProxy
);
instance = new SomeObject();
类似的东西应该有用
示例:
let foo = {bar: 'baz', method() { this.bar = 'baz2' }}
let fooProxy = new Proxy(foo, {set(target, key, val) { console.log('set trap triggered!') }})
fooProxy.bar = 'any value' // as expected: set trap triggered!
foo.method() // trap not triggered
为什么会这样?如何在目标对象内部执行触发陷阱?
编辑,主要是为了给@Bergi解释一下:
我的主要目标是拦截对 foo 对象的任何更改,因此我可以设置 属性 例如foo.changed 为真。另外,我想拦截对 array/object 类型的 foo 属性的更改。你知道,如果我设置 foo 的 属性,一切正常,但是当我例如推送到一个数组,然后代理无法拦截它。所以我也需要将 array/object 属性转换为代理(我称它们为 ArrayProxy 和 ObjectProxy)。
这是我的代码(打字稿):
// Category.ts
class Category extends Model {
title: string = ''
products: Product[] = []
}
// Model.ts
abstract class Model extends BaseModel {
constructor() {
return new Proxy(this, {
set (target, key, val) {
if (Array.isArray(val) {
target[key] = new ArrayProxy(val) // I WANT all array properties to be ArrayProxy but the problem (see below) not let me do that
}
}
})
}
}
// BaseModel.ts
abstract class BaseModel {
constructor(attributes) {
this.setAttributes(attributes)
}
setAttributes(attributes) {
Object.keys(attributes).forEach((key) => {
this[key] = attributes[key] // THE PROBLEM
})
}
}
我已经删除了代码,这无关紧要(例如,对象属性和 ObjectProxy 的类似情况)。
如果有更优雅的方法来完成我所做的,我将不胜感激。
在 foo.method
中,您没有通过代理对象设置 属性,因此显然不会触发任何陷阱。代理不修改原始对象。
原始对象上不存在陷阱。如果可以,您将不需要单独的代理对象。思路是用代理代替原来的。
一种可能是让您的原始对象继承自代理对象。这可能有效,具体取决于您实际需要完成的任务。
let fooProxy = new Proxy({}, {
set(target, key, val) { console.log('set trap triggered!') }
})
let foo = Object.create(fooProxy, {
method: {value: function() { this.bar = 'baz2' }}
})
fooProxy.bar = 'any value'
foo.method()
未触发设置陷阱,因为您在 method()
中访问的 this
不是代理而是原始对象 foo
。代理不会更改原始对象。您可以通过检查 this
里面的内容来查看 method()
:
let foo = {
method () {
return this === fooProxy
}
}
let fooProxy = new Proxy(foo, {})
document.write(foo.method()) //=> false
您可以使用 Function#call
:
method()
的上下文
let foo = {bar: 'baz', method() { this.bar = 'baz2' }}
let fooProxy = new Proxy(foo, {set(target, key, val) { console.log('set trap triggered!') }})
fooProxy.bar = 'any value' //=> set trap triggered!
foo.method.call(fooProxy) //=> set trap triggered!
您还可以将代理添加到对象原型中。
SomeObject.prototype = new Proxy(
SomeObject.prototype,
SomeObjectHandlerProxy
);
instance = new SomeObject();
类似的东西应该有用