代理事件目标上的 addEventListener

She*_*aff 5 javascript proxy addeventlistener javascript-objects dom-events

我正在尝试创建一个基本上既是 aProxy又是 an 的对象EventTarget对象。目标是能够订阅对此对象所做的任何更改。

这是我定义这个对象的方式:

const target = new EventTarget()
const state = new Proxy(target, { 
    set: (obj, key, value) => { 
        Reflect.set(obj, key, value)
        obj.dispatchEvent(new CustomEvent('change', {detail: {key, value}}))
    }, 
    deleteProperty: (obj, key) => { 
        Reflect.deleteProperty(obj, key) 
        obj.dispatchEvent(new CustomEvent('change', {detail: {key, value: undefined}})) 
    } 
})
Run Code Online (Sandbox Code Playgroud)

此时我希望能够打电话,state.addEventListener('change', console.log)但这给了我一个错误:

未捕获的类型错误:非法调用

所以这是有效的:

target.addEventListener('change', console.log)
state.foo = 'bar'
// logs the event
Run Code Online (Sandbox Code Playgroud)

但正如我所说,我希望有一个统一的对象,它既可以是目标(可以使用 监听addEventListener)又可以是值的存储(负责在修改时分派事件的代理对象)。到目前为止,这种方法只有在你随身携带并且 ……的target情况下才有效。state

知道为什么我不能通过 拨打addEventListener电话吗Proxy


从技术上讲,调用state.addEventListener()是通过原型方法进行的get,所以我尝试get: Reflect.get在代理处理程序中定义,但它没有添加任何内容...(尽管确实达到了,因为我console.log也尝试在那里添加)

那么为什么我不能通过addEventListener代理调用,但它直接在target对象上工作得很好呢?

She*_*aff 2

哦,没关系...我找到了答案...不过仍然发布它,因为它对我来说并不像我希望的那么简单,而且它可能会对某人有所帮助。


问题在于,当代理返回函数时,该函数没有正确的作用域 ( this)。因此,您需要将适当的范围绑定到返回的函数。

这可以通过定义 getter 来完成:

    get: function (obj, key) {
        const result = Reflect.get(obj, key)
        if(typeof result === 'function')
            return result.bind(obj)
        return result
    }
Run Code Online (Sandbox Code Playgroud)

完成后,就这么简单:

const state = new Proxy(new EventTarget(), handler)
state.addEventListener('change', console.log)
state.foo = 'bar'
// logs the event
Run Code Online (Sandbox Code Playgroud)

W3C 建议级别上,我不确定为什么 aProxy不应该返回具有适当范围的函数......