为什么不可枚举的属性不会影响数组的内置方法?

时间:2019-05-04 03:35:20

标签: javascript arrays object defineproperty

我正在使用方法Object.defineProperty()enumerable参数的descriptor属性。在MDN上,您可以阅读以下说明:

  

可枚举: true当且仅当在枚举相应对象的属性期间显示此属性时。默认为false

但是,我想知道它不影响遍历可迭代对象的方法(例如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;}

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

1 个答案:

答案 0 :(得分:3)

这是因为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不使用迭代器,非数组也不受数组迭代器的影响(尽管它们可能有自己的迭代器)