如何使用 Proxy 对象控制 属性 枚举(for...in)?
How to control property enumeration (for...in) with Proxy objects?
我将对象包装在 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
如果我 return "hello"
作为 ownKeys
的一部分,只会记录 "hello"
。
显然在 ES6 中有一个 enumerate
陷阱,但它已从 ES7 中删除。
是否仍然可以使用 Proxy 控制 for...in
循环?为什么 enumerate
从规范中删除?
很遗憾,不能再这样做了。
正如 Brian Terlson(EcmaScript 规范的编辑)所写:
issue with proxy enumerate trap and for-in, where iimplementations are
prevented from pre-populating the list of keys in the object, because
the iterator causes observable affects. Which means the iterate must
be pulled for every iteration. Last meeting we thought it would be ok
if the enumerate trap exhausts the iterator, we thought that would
solve the problem. The issue was, now their is an observable
difference between an object and proxy of that object, mainly due to
delete.
(来源:https://github.com/rwaldron/tc39-notes/blob/master/es7/2016-01/2016-01-28.md#5xix-proxy-enumerate---revisit-decision-to-exhaust-iterator via https://ecmascript-daily.github.io/2016/02/10/why-remove-enumerate-and-reflect-enumerate)
因此由于无法以令人满意的方式解决的技术挑战而将其删除。
有代理陷阱
仍然可以使用 has
proxy trap:
捕获 in
运算符本身
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()
(自己的属性和符号)
(来源:https://twitter.com/nilssolanki/status/659839340592422912)
(但您可能已经知道,首先看到您正在使用代理)
user2106769 将解决方案作为评论给出,但对于像我这样没有看到他们评论的其他人,您可以使用 ownKeys
和 getOwnPropertyDescriptor
覆盖 for..in
迭代:
var obj = { "hello": "world" };
var proxy = new Proxy(obj, {
ownKeys: function() {
return ["a", "b"];
},
getOwnPropertyDescriptor: function(target, key) {
return { enumerable: true, configurable: true, value: this[key] };
}
});
for (var key in proxy) {
console.log(key);
}
编辑:正如 Pärt Johanson 提到的,为了正确起见,getOwnPropertyDescriptor 应该返回“值”。
用户 user2106769 的建议和 yeerk 的覆盖 getOwnPropertyDescriptor 以允许枚举代理属性的回答有一个缺陷,在使用它时应该注意它,它在捕获 getOwnPropertyDescriptor 时不设置值属性,因此一些其他代码依赖于该行为的将无法正常运行。
演示该缺陷的代码及其解决方案如下:
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);
我将对象包装在 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
如果我 return "hello"
作为 ownKeys
的一部分,只会记录 "hello"
。
显然在 ES6 中有一个 enumerate
陷阱,但它已从 ES7 中删除。
是否仍然可以使用 Proxy 控制 for...in
循环?为什么 enumerate
从规范中删除?
很遗憾,不能再这样做了。
正如 Brian Terlson(EcmaScript 规范的编辑)所写:
issue with proxy enumerate trap and for-in, where iimplementations are prevented from pre-populating the list of keys in the object, because the iterator causes observable affects. Which means the iterate must be pulled for every iteration. Last meeting we thought it would be ok if the enumerate trap exhausts the iterator, we thought that would solve the problem. The issue was, now their is an observable difference between an object and proxy of that object, mainly due to delete.
(来源:https://github.com/rwaldron/tc39-notes/blob/master/es7/2016-01/2016-01-28.md#5xix-proxy-enumerate---revisit-decision-to-exhaust-iterator via https://ecmascript-daily.github.io/2016/02/10/why-remove-enumerate-and-reflect-enumerate)
因此由于无法以令人满意的方式解决的技术挑战而将其删除。
有代理陷阱
仍然可以使用 has
proxy trap:
in
运算符本身
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()
(自己的属性和符号)
(但您可能已经知道,首先看到您正在使用代理)
user2106769 将解决方案作为评论给出,但对于像我这样没有看到他们评论的其他人,您可以使用 ownKeys
和 getOwnPropertyDescriptor
覆盖 for..in
迭代:
var obj = { "hello": "world" };
var proxy = new Proxy(obj, {
ownKeys: function() {
return ["a", "b"];
},
getOwnPropertyDescriptor: function(target, key) {
return { enumerable: true, configurable: true, value: this[key] };
}
});
for (var key in proxy) {
console.log(key);
}
编辑:正如 Pärt Johanson 提到的,为了正确起见,getOwnPropertyDescriptor 应该返回“值”。
用户 user2106769 的建议和 yeerk 的覆盖 getOwnPropertyDescriptor 以允许枚举代理属性的回答有一个缺陷,在使用它时应该注意它,它在捕获 getOwnPropertyDescriptor 时不设置值属性,因此一些其他代码依赖于该行为的将无法正常运行。
演示该缺陷的代码及其解决方案如下:
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);