[英]ES6 Proxy: set() trap not triggering, when setting inside target object's method
Example:示例:
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
Why does this happen?为什么会发生这种情况? How can triggering trap be enforced even from inside target object?
即使从目标对象内部,如何触发陷阱?
Edit, mainly in order to explain this to @Bergi:编辑,主要是为了向@Bergi解释这一点:
My main goal is to intercept any changes to foo object, so i can set property eg foo.changed to true.我的主要目标是拦截对 foo 对象的任何更改,因此我可以将 foo.changed 等属性设置为 true。 Also, I want intercept changes to foo's properties which have array/object type.
另外,我想拦截对具有数组/对象类型的 foo 属性的更改。 You know, if I am setting foo's property, everything is ok, but when I eg push to one that is array, then proxy cannot intercept that.
您知道,如果我正在设置 foo 的属性,则一切正常,但是当我例如推送到数组时,代理无法拦截它。 So I need to convert array/object properties to proxies too (I called them ArrayProxy and ObjectProxy).
所以我也需要将数组/对象属性转换为代理(我称它们为 ArrayProxy 和 ObjectProxy)。
Here's my code (typescript):这是我的代码(打字稿):
// 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
})
}
}
I've removed code, that does not matter (eg similar case for object properties and ObjectProxy).我已经删除了代码,这无关紧要(例如,对象属性和 ObjectProxy 的类似情况)。
I will appreciate very much, if there is more elegant way to do what I've done.如果有更优雅的方式来做我所做的事情,我将非常感激。
The trap doesn't exist on the original object.陷阱不存在于原始对象上。 If it could, you wouldn't need a separate proxied object.
如果可以,您就不需要单独的代理对象。 The idea is to use the proxy instead of the original.
这个想法是使用代理而不是原始的。
One possibility is to have your original object inherit from a proxied object.一种可能性是让您的原始对象从代理对象继承。 This could work, depending on what you actually need to accomplish.
这可能会起作用,具体取决于您实际需要完成的工作。
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()
The set trap is not triggered because the this
that you are accessing within method()
is not the proxy but the original object foo
.不会触发设置陷阱,因为您在
method()
中访问的this
不是代理而是原始对象foo
。 A proxy does not change the original object.代理不会更改原始对象。 You can see this by checking what
this
is inside method()
:您可以通过检查
method()
this 来查看这this
:
let foo = { method () { return this === fooProxy } } let fooProxy = new Proxy(foo, {}) document.write(foo.method()) //=> false
You could instead explicitly set the context of method()
on invocation by using Function#call
:您可以改为使用
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!
You can also add the proxy to the object prototype.您还可以将代理添加到对象原型中。
SomeObject.prototype = new Proxy(
SomeObject.prototype,
SomeObjectHandlerProxy
);
instance = new SomeObject();
something like should work像应该工作
In foo.method
you're not setting a propery through the proxy object, so obviously no trap is triggered.在
foo.method
您没有通过代理对象设置属性,因此显然没有触发陷阱。 A Proxy does not modify the original object.代理不会修改原始对象。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.