Как управлять перечислением свойств (для...in) с объектами 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"
зарегистрирован
Видимо был enumerate
ловушка в ES6, но она была удалена из ES7.
Можно ли по-прежнему контролировать for...in
цикл с прокси? Почему enumerate
удалены из спецификации?
2 ответа
К сожалению, это невозможно сделать больше.
Как писал Брайан Терлсон (редактор спецификации EcmaScript):
проблема с прокси-перечислением trap и for-in, когда iimplementations не могут предварительно заполнить список ключей в объекте, потому что итератор вызывает наблюдаемые эффекты. Это означает, что итерация должна выполняться для каждой итерации. На прошлой встрече мы думали, что было бы хорошо, если бы перечисляемая ловушка исчерпала итератор, мы думали, что это решит проблему. Проблема заключалась в том, что в настоящее время существует заметная разница между объектом и прокси этого объекта, главным образом из-за удаления.
(Источник: 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
ловушка прокси:
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 предоставил решение в качестве комментария, но для любого, как я, который не видел их комментарий, вы можете переопределить for..in
итерация с 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 для разрешения перечисления атрибутов Proxy имеет недостаток, о котором следует знать при его использовании, он не устанавливает атрибут value при перехвате 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);