为什么 non-enumerable 属性不影响数组 built-in 方法?

Why non-enumerable properties don't affect the array built-in methods?

我在玩Object.defineProperty()descriptor 参数的enumerable 属性 方法。在 MDN 你可以阅读下一个描述:

enumerable: true if and only if this property shows up during enumeration of the properties on the corresponding object. Defaults to false.

但是,我想知道为什么它不影响遍历可迭代 objects 的方法,例如 for ... of。在下一个示例中,您可以看到使用 for ... offor ... in.

遍历数组之间的比较

let arr = [1, 2, 3, 4, 5];
Object.defineProperty(arr, "4", {value: 99, enumerable: false});

console.log("For ... of traverse non-enumerable properties:");

for (const ele of arr)
{
    console.log(ele);
}

console.log("For ... in don't traverse non-enumerable properties:");

for (const key in arr)
{
    console.log(arr[key]);
}
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}

此外,正如这个问题的标题所述,built-in 数组方法也忽略此设置,但 object 方法不会:

let arr = [1, 2, 3, 4, 5];
Object.defineProperty(arr, "4", {value: 99, enumerable: false});

console.log("forEach(): ");
arr.forEach(x => console.log(x));

console.log("map(): ", arr.map(x => x + 1));

console.log("reduce(): ", arr.reduce((acc, x) => `${acc + x},` , ""));

console.log("Object.keys(): ", Object.keys(arr));

console.log("Object.values(): ", Object.values(arr));
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}

我并不是说这是错误的或意外的行为,只是在寻找对这种情况的解释,谢谢!

因为way the array iterator is specified。虽然定义每个键的密集数组是最常见的,但也支持稀疏数组,其中只定义了少数键。为了支持这一点,数组迭代需要能够迭代过去实际不存在的键。例如:

const arr = [];
arr[0] = 0;
arr[10] = 10;

console.log('has 0?', arr.hasOwnProperty(0))
console.log('has 1?', arr.hasOwnProperty(1))

for (let val of arr) {
  console.log(val);
}

基本上,迭代器的定义方式是从一个数字索引移动到下一个数字索引,直到达到数组的长度。在此过程中,它不会检查这些索引是否可枚举,甚至它们是否存在。

For ... of 使用迭代器,因此受此影响,一些数组方法也是如此。 For ... in 不使用迭代器,非数组也不受数组迭代器的影响(尽管它们可能有自己的迭代器)