简体   繁体   English

ES6 代理:set() 陷阱不触发,当在目标对象的方法中设置时

[英]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.

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