Javascript V8:ES6代理不';针对自定义对象时是否支持迭代协议?

Javascript V8:ES6代理不';针对自定义对象时是否支持迭代协议?,javascript,proxy,ecmascript-6,v8,Javascript,Proxy,Ecmascript 6,V8,我正在使用V8 API创建JavaScript对象。其中一些对象通过在Symbol.iterator属性处设置本机(拦截)函数来支持迭代 通过迭代这样一个对象非常有效。但是,如果我将其包装在一个空代理中(例如,let x=new proxy(obj,{});),则生成的对象是不可编辑的,如果试图对其进行迭代,就会抛出一个带有消息“非法调用”的TypeError 包装标准阵列不会出现此问题。这是一个V8错误吗 包装标准阵列不会出现此问题 是的,就是这样工作的。他们不关心他们正在迭代的对象的类型-他

我正在使用V8 API创建JavaScript对象。其中一些对象通过在
Symbol.iterator
属性处设置本机(拦截)函数来支持迭代

通过迭代这样一个对象非常有效。但是,如果我将其包装在一个空代理中(例如,
let x=new proxy(obj,{});
),则生成的对象是不可编辑的,如果试图对其进行迭代,就会抛出一个带有消息“非法调用”的
TypeError

包装标准阵列不会出现此问题。这是一个V8错误吗

包装标准阵列不会出现此问题

是的,就是这样工作的。他们不关心他们正在迭代的对象的类型-他们只是访问它的
.length
和索引属性(通常通过代理路由)

然而,其他标准的异国情调对象也没有表现得那么好。如果您试图调用
[Symbol​.迭代器]()
在一个或封装在代理中的对象上,它们会抱怨在错误的对象上被调用

这是一个V8错误吗

不,这是应用程序中的一个bug。您有三个选择:

  • 创建一个迭代器,该迭代器不依赖于自定义对象的内部插槽,而是使用它们的公共(代理可拦截)属性接口。确保您的
    [Symbol.iterator]
    方法没有对其接收器进行类型检查
  • 检查迭代器方法中的接收器类型,如果它是代理(即具有
    [[ProxyTarget]]]
    内部插槽),则使用该值。我强烈建议不要这样做,因为它不符合标准行为,并且在绕过处理程序时违反了代理
  • 不要使用空代理:

    let x = new Proxy(obj, {
        get(target, key, receiver) {
           if (key === Symbol.iterator)
               return target[Symbol.iterator].bind(target);
           else
               return Reflect.get(target, key, receiver);
        }
    });
    

如果将其包装在空代理中,您希望迭代什么?@Pogrindis我希望代理在其目标上迭代;如果目标是标准阵列,就会发生这种情况。谢谢你的回答,@Bergi。你是对的;问题是,我的
[Symbol.iterator]
方法要求其持有者具有某些私有字段,当持有者是代理时,这些字段是不可访问的。快速跟进问题:您知道为什么
proxy[Symbol.iterator]()
在不调用我的拦截器的情况下抛出异常,而
it=proxy[Symbol.iterator];它()
调用拦截器并按预期崩溃?如果这是您所说的“拦截器”的意思,那么这两者都应该调用
get
处理程序?我无法想象为什么不会。对不起,让我试着澄清一下。我没有指定自定义
get
处理程序;该方法作为普通属性存储在目标上,并且在这两种情况下都可以正确检索。我不明白的是,为什么第一个语法在不调用方法的情况下抛出异常,而第二个语法调用方法并按预期崩溃。方法本身是一个本机函数,其调用会导致回调到本机(C++)代码中,但这与AICT无关。明显的区别是接收者(
proxy
vs
undefined
),这是js函数中的
this
关键字的值,但我不知道本机函数是如何受到影响的。显然,有一些防护措施阻止您的自定义函数运行,但我不知道V8的详细信息。它也发生在非代理对象上吗;这种差异似乎存在于V8的函数调用机制中。如果
x
是本机函数而
y
是代理函数,则调用(y)会提前失败。