for.in 遍历属性是否被原型链中的非可枚举属性覆盖?


for..in

根据ES6 遍历所有可枚举String属性,它是否需要访问相同的属性,因为它被其十进制中的非可枚举属性覆盖(相同的属性字符串)?就像下面的代码一样Object.prototype.indexOf没有遍历Array。上面链接中的 pseduo 代码仅暗示重复的可枚举属性不会再次枚举,并且似乎不包括这种情况。

Object.prototype.indexOf = "test";
var arr = [];
for (var item in arr) {
// Object.prototype.indexOf is overwritten for arr by Array.prototype.indexOf,
// the latter is non-enumerable
console.log(item);
}

否,不枚举不可枚举的属性名称。无论它们是否隐藏可枚举的继承属性。

您的测试和链接的规范文本都确认了这一点:

[...]如果原型的属性与已处理的属性具有相同的名称,则不会对其进行处理[...]

for...in循环迭代 EnumerateObjectProperties 迭代器给出的属性。

枚举

目标对象的属性包括枚举 其原型的属性,以及原型的原型,以及 依此类推,递归;但是在以下情况下不会处理原型的属性 它与已由 迭代器的next方法。[[可枚举]] 属性的值 在确定原型的属性时不考虑 对象已被处理。

所以是的,如果你的对象有一个不可枚举的属性,它将被处理,但不会被迭代。如果在原型链中存在相同的属性,但现在可枚举,则将将其视为已处理,因此不会迭代。

您可以在建议的实现代码中看到,键始终添加到访问的集合中,即使由于不可枚举性而未生成。

function* EnumerateObjectProperties(obj) {
let visited = new Set;
for (let key of Reflect.ownKeys(obj)) {
if (typeof key === "string") {
let desc = Reflect.getOwnPropertyDescriptor(obj, key);
if (desc && !visited.has(key)) {
visited.add(key); // <-- Added even if not enumerable
if (desc.enumerable) yield key;
}
}
}
let proto = Reflect.getPrototypeOf(obj)
if (proto === null) return;
for (let protoName of EnumerateObjectProperties(proto)) {
if (!visited.has(protoName)) yield protoName;
}
}

最新更新