Are "Empty" values within an array not eternal?

Asked

Viewed 74 times

3

In this code snippet:

let arr = []; 
arr[3] = null;

The following excerpt arr[3] = null; makes the array size according to the value within the array annotation []. The forEach will be used to work with the contents of this array.

var arr2 = []

arr2[2] = null

console.log(arr2)

// vai exibir somente o 'null 2'
arr2.forEach((el, i) => {
 console.log(el, i)
})

If you run the following code above in the browser, console.log(arr2) will display something like:

(3) [empty × 2, null]

In the OS snippet, it displays undefined, I don’t know why...

Based on that, I ask:

  • That "value" empty is not eternal by the method forEach? And by other functional methods(map, filter, ...)?
  • That one empty apparently not the same as undefined, right? What is this value?
  • 1

    Related (and perhaps dup): https://answall.com/q/471070/112052

  • 1

    @hkotsubo, indeed related, but, duplicated, I don’t think so. The focus of the question is another, its answer tangentially this subject because of the great deepening. If it is duplicate... I would say not.

  • 1

    @hkotsubo actually has some interesting points on P/R. But the intention was to talk about specifically the array "holes". I agree with Felipe in this case. But thanks anyway :D

1 answer

3


Congratulations, you just discovered the bumpy arrays in Javascript!


When you create an array and assign it a value in an index beyond its limits, it will "punch" the array. For example:

let arr = [];
arr[3] = 'Final element'; // Atribui essa string ao quarto elemento (índice 3).

When trying to evaluate arr in the Chrome Console, for example, something like:

(4) [empty × 3, "Final element"]

Note that in fact the array has length 4, since it was the last index assigned. However, the first three elements of the array are... empty.

With examples like this, many people think that empty is another type of Javascript value, such as a undefined or null. However, empty does not exist in Javascript. It was only printed by the Console to demonstrate array positions that have no elements.

An array in Javascript is nothing more than a mere object. Thus, an array like ['a', 'b', 'c'], quite simply, it can be summed up to this:

{
  0: 'a',
  1: 'b',
  2: 'c',
  length: 3
}

So that a bumpy array does not have all the indexes in the expected numerical sequence. Returning to the example of the beginning of this answer, the array arr could be summarized to:

{
  3: 'Final element',
  length: 4
}

And that’s exactly what the empty printed on the Console represents! The complete absence of the property. It is the same as an object without a certain property.

When a programmer creates a bumpy array and tries to access an empty position, it returns undefined. It is the same thing as trying to access a property that does not exist in an object, after all, arrays are Javascript objects.

Note that this does not mean that the array has an index with element undefined. He just doesn’t have anything there.


This means the array is no longer iterable?

No, not at all.

Formally speaking, a "everlasting" Javascript is every value that implements a qualified iterator under the symbolic name @@iterator. In the case of bumpy arrays, this method does not cease to exist. See:

let arr = [];
arr[3] = 'Final element';

// Continua sendo iterável. Pode-se testar isso consumindo o iterador via `for..of`.
for (const element of arr) {
  console.log(element);
}

The specification defines which empty elements should be included in the standard iteration protocol of arrays, such as undefined. The example above demonstrates this.

Note that the iteration protocol consumes all array positions (including empty positions, in this case, generating undefined).


And as for the for "classic"?

Nothing prevents you from traversing the array from zero index to its length, not inclusive. See:

let arr = [];
arr[3] = 'Final element';

for (let i = 0; i < arr.length; i++) {
  console.log(arr[i]);
}

What happens in the example above is that we are literally trying to access properties qualified by numbers of 0 up to array length minus 1. Of course, in bumpy arrays, some of these indexes will not be existing properties, cases in which undefined is returned.

With the for "classic" we can further attest that the empty elements are not, in fact, array properties. The undefined which is printed in the above example is due to a non-existent property attempt to the array object. This behaviour has already been explained earlier in this reply.

Note that empty elements are not, in fact, properties:

let arr = [];
arr[3] = 'Final element';

for (let i = 0; i < arr.length; i++) {
  console.log(`Has element at index ${i}? ${i in arr}`);
}


What about the methods of Array.prototype, just as forEach or map?

In this case there may be strangeness. Javascript being Javascript.

Methods of Array.prototype such as forEach, map, filter, reduce, some, every (and others) nay operate on elements that do not exist in the array.

That way, this type of method will simply ignore empty members.

This implies that if you have an array with four positions, but three of them are empty, only one iteration will be apparent to the programmer. Note the "apparent" because, internally, all indexes up to length - 1 are covered, but the specification does not invoke the callback of these methods for elements that do not exist as property.

For example, look at this forEach and map:

let arr = [];
arr[3] = 'Final element';

// O callback será invocado somente uma vez:
// Somente uma mensagem será impressa:
arr.forEach((element, index) => {
  console.log(`At index ${index}, the element is: ${element}`);
});

// O callback será invocado somente uma vez:
const mapped = arr.map((element, index) => {
  return `At index ${index}, the element is: ${element}`;
});

// OS BURACOS SÃO MANTIDOS no array mapeado.
// O snippet do SOpt mostra de modo incorreto.
// Saída esperada: (4) [empty × 3, "At index 3, the element is: Final element"]
console.log(mapped);

This type of behaviour is specified in the specification for each of these methods. For example, in the case of forEach, we can refer to the Section 22.1.3.12, that, in summary:

  • For each index Pk (Pk < length) array,
    • If the array (object) has property whose key is Pk, invoke the callback.
    • Otherwise, increase the index.

Note that the specification explicitly defines indices that do not reflect a property in the array object nay must invoke the callback of forEach. Rules similar to this exist for filter, map, reduce, etc..


In short, think of arrays holes as an index that literally does not exist in the array.

Just out of curiosity, totally empty arrays can be created by the builder Array called as a function. For example, Array(5) will create an array with length 5, its "5 element" being empty. In this case, this implies that only the property length will be defined in that array.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.