4

例子:

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)设置为 true。另外,我想拦截对具有数组/对象类型的 foo 属性的更改。你知道,如果我设置 foo 的属性,一切都很好,但是当我推送到一个数组时,代理无法拦截它。所以我也需要将数组/对象属性转换为代理(我称它们为 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 的类似情况)。

如果有更优雅的方式来做我所做的事情,我将非常感激。

4

4 回答 4

2

原始对象上不存在陷阱。如果可以,您将不需要单独的代理对象。这个想法是使用代理而不是原始的。

一种可能性是让您的原始对象继承自代理对象。这可能会起作用,具体取决于您实际需要完成的工作。

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()

于 2018-04-04T14:52:23.773 回答
1

设置陷阱不会被触发,因为this您在其中访问method()的不是代理而是原始对象foo。代理不会更改原始对象。您可以通过检查this里面的内容来看到这一点method()

let foo = {
  method () {
    return this === fooProxy
  }
}
let fooProxy = new Proxy(foo, {})
document.write(foo.method()) //=> false

method()您可以改为使用以下命令显式设置调用上下文Function#call

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!

于 2018-04-04T14:54:27.517 回答
1

您还可以将代理添加到对象原型。

SomeObject.prototype = new Proxy(
    SomeObject.prototype,
    SomeObjectHandlerProxy
);

instance = new SomeObject();

像应该工作的东西

于 2021-07-14T23:20:47.753 回答
0

由于foo.method您没有通过代理对象设置属性,因此显然不会触发陷阱。代理不会修改原始对象。

于 2018-04-04T14:52:09.403 回答