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

时间:2016-12-08 06:02:54

标签: javascript

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

2 个答案:

答案 0 :(得分:2)

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

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

  

[...]如果原型的属性与已经处理的属性同名,则不处理该原型的属性[...]

答案 1 :(得分:1)

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

  

枚举目标对象的属性包括枚举   它的原型的属性,原型的原型,和   等等,递归地;但如果是,则不处理原型的属性   它与已经处理过的属性具有相同的名称   迭代器的next方法。 [[Enumerable]]属性的值   在确定原型的属性时不考虑   对象已被处理。

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

您可以在建议的实现代码中看到密钥总是被添加到访问集中,即使由于不可枚举而没有产生。

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