如何使用Proxy对象控制属性枚举(for ... in)?

时间:2016-07-26 09:47:21

标签: javascript proxy-object

我将一个对象包装在Proxy中,然后遍历它。如何控制它迭代的键?

如果我不覆盖密钥,代理就可以工作:

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中有一个enumerate陷阱,但它已从ES7中删除。

是否仍然可以使用代理控制for...in循环?为什么enumerate已从规范中删除?

3 个答案:

答案 0 :(得分:8)

不幸的是,再也不可能这样做了。

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

  代理枚举陷阱和for-in的问题

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

(来源:https://github.com/rwaldron/tc39-notes/blob/master/es7/2016-01/2016-01-28.md#5xix-proxy-enumerate---revisit-decision-to-exhaust-iterator通过https://ecmascript-daily.github.io/2016/02/10/why-remove-enumerate-and-reflect-enumerate

因为技术挑战无法以令人满意的方式解决,所以它被删除了。

代理陷阱

in运算符仍然可以使用has proxy trap

捕获
var p = new Proxy({}, {
  has: function(target, prop) {
    if (prop === 'a') { return true; }
    return false;
  }
});
'a' in p; // true
'b' in p; // false

<强>替代

由于for (let key in proxy)循环现在更像是传统功能,因此您可以使用以下ownKeys代理陷阱之一:

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

enter image description here (来源:https://twitter.com/nilssolanki/status/659839340592422912

(但你可能已经知道,首先看到你正在使用代理)

答案 1 :(得分:2)

user2106769将解决方案作为评论提供,但对于像我这样没有看到他们评论的其他人,您可以使用for..inownKeys覆盖getOwnPropertyDescriptor次迭代:< / p>

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);
}

答案 2 :(得分:0)

用户user2106769的建议和yeerk的回答,即重写getOwnPropertyDescriptor以允许枚举Proxy属性有一个缺陷,使人在使用它时应该意识到这一缺陷,它在捕获getOwnPropertyDescriptor时不会设置value属性,因此,依赖于其他代码这种行为将无法正常运行。

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

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

var goodProxy = new Proxy(obj, {
    get: function(target, key) {
      // modify something here if you want to
      return target[key];
    },
    ownKeys: function() {
        return ["a", "b"];
    },
    getOwnPropertyDescriptor: function(target, key) {
         return { value: this.get(target, key), enumerable: true, configurable: true };
    }
});

// value is accessible, getOwnPropertyDescriptor not trapped
console.log(Object.getOwnPropertyDescriptor(obj, 'hello').value);

// value is undefined, getOwnPropertyDescriptor not trapped correctly
console.log(Object.getOwnPropertyDescriptor(flawedProxy, 'hello').value);

// value is accessible, getOwnPropertyDescriptor trapped correctly
console.log(Object.getOwnPropertyDescriptor(goodProxy, 'hello').value);