1

I was playing with the method Object.defineProperty() and the enumerable property of the descriptor argument. On the MDN you can read the next description:

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

However, I'm wonder about the reason it don't affect methods that traverse iterable objects, like the for ... of. On the next example you can see the comparison between traversing the array using for ... of and for ... 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;}

Also, as the title of this question mention, built-in array methods ignores this setting too, but object methods don't:

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

I'm not saying this is wrong or unexpected behavior, but just looking for an explanation of this situation, thanks!

Shidersz
  • 16,846
  • 2
  • 23
  • 48
  • I'm not sure I understand your question, it can probably do with a bit of a rewrite to make it clearer in terms of what it is you're actually asking: ask your question, then show the code you used for your own tests, then explain what you expected to see, what you saw instead, and why (for each difference) that wasn't what you expected? – Mike 'Pomax' Kamermans May 04 '19 at 03:49
  • 1
    @Mike'Pomax'Kamermans First of all, sorry if i'm not so clear. English is not my native language, so I abuse of Google translate. I just want to understand why array `built-in` methods that traverse the array don't get affected by `non-enumerable` properties (after all, arrays are special objects). By now, I'm asuming that configuration only affects some object methods. – Shidersz May 04 '19 at 04:02
  • 1
    Related doc [iterator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/iterator) – hackape May 04 '19 at 04:35

1 Answers1

3

It's because of the way the array iterator is specified. While it's most common to have dense arrays where every key is defined, sparse arrays are also supported, where only a handful of keys are defined. To support this, array iteration needs to be able to iterate past keys that don't actually exist. For example:

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

So basically, the iterator is defined in such a way that it moves from one numerical index to the next until it reaches the length of the array. Along the way, it does not check whether those indexes are enumerable, or even if they exist at all.

For ... of uses the iterator and thus is affected by this, as are some array methods. For ... in does not use the iterator, and non-arrays are also not affected by the array iterator (though they may have their own iterators)

Nicholas Tower
  • 72,740
  • 7
  • 86
  • 98
  • Thanks for your explanation, this and the `iterator` link mentioned in the comments helps me to understand. So, basically `non-enumerable` property don't affect methods that traverse special objects (as arrays, maps or sets) using iterators, they only affects methods that traverse the enumerable properties of an object. – Shidersz May 04 '19 at 16:02