2

I was reading Trailing commas and .forEach() documentations on MDN meanwhile playing with arrays.

So let's imagine a scenario when you have an array with elements like Number, undefined and created ones with trailing commas and running a forEach() on that. See from the documentation:

forEach() calls a provided callback function once for each element in an array in ascending order. It is not invoked for index properties that have been deleted or are uninitialized.

Based on that it skips the elements created with trailing commas but not the undefined ones:

const array = [ 1, 2, , 4, , undefined, ];
console.log({ length: array.length }); // shows 6

array.forEach((e, i) => console.log({e, i})); // logging 4 elements

In the same time using traditional for loop it logs all the elements as expected:

const array = [ 1, 2, , 4, , undefined, ];
console.log({ length: array.length }); // shows 6 as before

for (let i = 0; i < array.length; i++) {
  console.log({e: array[i], i}); // logs 6 elements
}

Also Chrome developer tool is showing empty items for the array for ones created by trailing commas:

chrome-screenshot

My questions:

From the documentation I found .forEach() is skipping deleted or uninitialized elements when iterating. So I see that statement, that's how it has been built.

So my questions would be:

  1. What's the difference between the undefined directly added to the array and by the trailing commas?
  2. Why .forEach() is showing up one undefined which has been added but not all the other ones.
  3. How can you differentiate from items called empty and undefined in this term?

What is going on under the hood? Can someone enlighten me about this scenario?

Appreciate the clarification, thank you!


Update:

I think I understood after further reading based on the linked questions.

So I took a look how .forEach() has been implemented which has an extra check with in operator for each elements and that's the difference. See as the following:

const array = [ 1, 2, , 4, , undefined, ];
console.log({ length: array.length }); // shows 6 as before

for (let i = 0; i < array.length; i++) {
  console.log({e: array[i], i, has: i in array});
}

So for the directly added undefined element the i in array returns true for all the empty elements false which makes sense now. As a result .forEach only calls the callback once the current element is existing.

Thanks for all the comments!

norbitrial
  • 12,734
  • 5
  • 20
  • 46
  • 2
    Setting something to `undefined` is still setting it--you initialized it w/ `undefined`. "Under the hood" it knows which elements you've defined. – Dave Newton Apr 27 '20 at 14:40
  • 1
    You're initializing the item with `undefined`, but if you leave an `empty space` you know an item must be there, but it wasn't initialized, it has no `value/type` so it's skipped on `.forEach()`. – Triby Apr 27 '20 at 14:41
  • 2
    Notice that a *trailing* comma is just ignored, as if you never had written it. A comma that creates an elision is never a trailing comma. – Bergi Apr 27 '20 at 14:44
  • 1
    Arrays are sparse, the "empty" elements don't exist. Run this: `Object.getOwnPropertyDescriptors(array)`. – terrymorse Apr 27 '20 at 14:45
  • @terrymorse arrays *can be* sparse. Not all arrays are, though. – VLAZ Apr 27 '20 at 14:58
  • @VLAZ Fair enough, I'll restate: the array in *this* example is sparse. – terrymorse Apr 27 '20 at 15:08
  • Thanks for all the comments, it makes sense now, just extended my question with my understanding for the scenario with `in` operator. Thanks again! – norbitrial Apr 27 '20 at 15:40

0 Answers0