为什么设置与代理不兼容?

use*_*349 5 javascript proxy

JavaScript 似乎与JavaScript 代理完全不兼容,试图Proxy()使用Set()

var p = new Proxy(new Set(), {
  add(target, val, receiver) {
    console.log('in add: ', target, val, receiver)
  }
})
p.add(55)
Run Code Online (Sandbox Code Playgroud)

导致VMError:

Uncaught TypeError: Method Set.prototype.add called on incompatible receiver [object Object]
    at Proxy.add (native)
    at <anonymous>:1:3
Run Code Online (Sandbox Code Playgroud)

事实上,代理a Set()以任何方式断断续续 - 即使我们的代理处理程序什么都不做!比较p = new Proxy({}, {})VS p = new Proxy(new Set(), {}).(这适用于Firefox(52.0.2)和Chromium(57.0.2987.133).)

我似乎无法为此找到可信的参考或文档,为什么JavaScript不能Proxy成为Set对象,为什么它会遇到VM错误?

Ber*_*rgi 6

我试图Proxy()Set()

但是,您没有使用任何可用的陷阱 - 没有add人.所有这一切,你可以在调用拦截p.add(55)属性访问.add的代理,其经过的get陷阱,并返回一个函数.

如果你想拦截对该add方法的调用,你根本不需要代理,更好(子类和)覆盖该方法类似于在这里这里.set重写的方式.Map

代理a Set()以任何方式断断续续地打破它

是的,因为代理不再是代理Set.

var s = new Set([42]);
var p = new Proxy(s, {});
s.has(42) // true
console.log(s === p) // false
p.has.call(s, 42) // true
p.has(42) // exception - calls `has` on `p`, not on `s`
Run Code Online (Sandbox Code Playgroud)

Set在没有True Sets的对象上调用方法会抛出异常(例如可以用于检测它们).有关您的具体情况,请参阅ECMAScript6§23.2.3.1:

" 如果S没有[[SetData]]内部插槽,则抛出TypeError异常. "

实际上,它p是一个代理(它具有内部代理方法和插槽,特别是[[ProxyHandler]][[ProxyTarget]])而不是像s[[SetData]]内部插槽一样的集合.

您有理由期望" 如果尚未定义陷阱,则默认行为是将操作转发到目标 ",但这仅适用于属性访问等标准行为,而不适用于外来对象的内部插槽.