Javascript 如何使用代理对象控制属性枚举(针对…中)?

Javascript 如何使用代理对象控制属性枚举(针对…中)?,javascript,proxy-object,Javascript,Proxy Object,我将一个对象包装在一个容器中,然后遍历它。我如何控制它遍历的键 如果我不覆盖密钥,代理将起作用: var obj = {"hello": "world"} var proxy = new Proxy(obj, {}) for (var key in proxy){ console.log(key) } // logs "Hello" 但是,如果我更改ownKeys处理程序中的键,则不会记录任何内容 var obj = {"hello": "world"} var proxy = new

我将一个对象包装在一个容器中,然后遍历它。我如何控制它遍历的键

如果我不覆盖密钥,代理将起作用:

var obj = {"hello": "world"}
var proxy = new Proxy(obj, {})
for (var key in proxy){
    console.log(key)
}
// logs "Hello"
但是,如果我更改
ownKeys
处理程序中的键,则不会记录任何内容

var obj = {"hello": "world"}
var proxy = new Proxy(obj, {
    ownKeys: function(){
        return ["a", "b"]
    }
})
for (var key in proxy){
    console.log(key)
}
// Logs nothing
如果我返回
“hello”
作为
ownKeys
的一部分,则只记录
“hello”

显然,ES6中有一个陷阱,但它已从ES7中移除


是否仍然可以使用代理控制循环中的for?为什么从规范中删除了枚举?

不幸的是,现在不可能再这样做了

正如Brian Terlson(EcmaScript规范的编辑)所写:

代理枚举陷阱和中的问题,其中iI实现是 阻止预填充对象中的键列表,因为 迭代器产生可观察的影响。这意味着迭代必须 在每次迭代中都会被拉。上次会议我们认为可以 如果枚举陷阱耗尽迭代器,我们认为这会 解决问题。问题是,现在他们的行为是可以观察到的 对象和该对象的代理之间的差异,主要是由于 删除

(来源:via)

因此,由于无法以令人满意的方式解决技术挑战,它被删除

有代理陷阱

仍然可以使用以下命令捕获中的

备选方案

由于(
for(let key in proxy)
循环现在更像是一种遗留功能,因此您可以将以下选项之一用于
ownKeys
代理陷阱:

  • Object.keys()
    (仅限自己的可枚举属性)
  • Object.getOwnPropertyNames()
    (自有属性)
  • Reflect.ownKeys()
    (自己的属性和符号)
(来源:)


(但您可能已经知道,因为您首先使用的是代理)

用户2106769以注释的形式给出了解决方案,但是对于像我这样没有看到他们注释的任何人,您可以覆盖
for..在
迭代中使用
ownKeys
getOwnPropertyDescriptor

var obj = { "hello": "world" };
var proxy = new Proxy(obj, {
    ownKeys: function() {
        return ["a", "b"];
    },
    getOwnPropertyDescriptor: function(target, key) {
        return { enumerable: true, configurable: true };
    }
});
for (var key in proxy) {
    console.log(key);
}

用户user2106769建议和yeerk关于覆盖getOwnPropertyDescriptor以允许代理属性枚举的回答有一个缺陷,在使用它时应该注意,它在捕获getOwnPropertyDescriptor时没有设置value属性,因此依赖于该行为的其他一些代码将无法正常运行

演示该缺陷及其解决方案的代码如下:

var obj={“你好”:“世界”};
var DefectedProxy=新代理(obj{
ownKeys:function(){
返回[“a”、“b”];
},
getOwnPropertyDescriptor:函数(目标,键){
返回{可枚举:true,可配置:true};
}
});
var goodProxy=新代理(obj{
get:函数(目标、键){
//如果需要,请在此处修改某些内容
返回目标[键];
},
ownKeys:function(){
返回[“a”、“b”];
},
getOwnPropertyDescriptor:函数(目标,键){
返回{value:this.get(target,key),可枚举:true,可配置:true};
}
});
//值是可访问的,getOwnPropertyDescriptor未被捕获
log(Object.getOwnPropertyDescriptor(obj,'hello').value);
//值未定义,getOwnPropertyDescriptor未正确捕获
log(Object.getOwnPropertyDescriptor(有缺陷的代理,'hello').value);
//值是可访问的,getOwnPropertyDescriptor被正确捕获

log(Object.getOwnPropertyDescriptor(goodProxy,'hello').value)谢谢,回答得真棒。我正好处在这样一个环境中,我可以使用Babel在执行之前修改代码,这样我就可以添加自定义逻辑。我可以使用Babel在执行之前修改代码,这样我就可以添加自定义逻辑。我不完全明白你的意思。你能详细说明一下吗?基本上,我可以在代码运行之前对其进行转换,这样我就可以用其他东西替换
for…in
循环,或者更新它以包含我的逻辑。在大多数生产环境中,这不是您可以做的事情,但是我已经在使用的代码上运行了Babel,所以这不是问题。for(key-in-proxy)可以实现。正如Nils所说,您需要实现ownKeys代理陷阱,并且可能还需要实现getOwnPropertyDescriptor代理陷阱,以便将它们设置为可枚举!您还需要实现getOwnPropertyDescriptor代理陷阱,以将它们设置为可枚举!这不是陷阱工作原理的一个缺陷吗?似乎。应该设置值。与生产中需要的相比,这似乎过于简化了。在某些情况下,可枚举和可配置不需要为false吗?仅仅将整个对象重写为true可能会导致问题?
var obj = { "hello": "world" };
var proxy = new Proxy(obj, {
    ownKeys: function() {
        return ["a", "b"];
    },
    getOwnPropertyDescriptor: function(target, key) {
        return { enumerable: true, configurable: true };
    }
});
for (var key in proxy) {
    console.log(key);
}