First of all, it is worth remembering that Undefined
is one of the types defined by the language (as well as String
, Number
, Boolean
, etc.). And the specification says the following:
The Undefined type has Exactly one value, called Undefined. Any variable that has not been Assigned a value has the value Undefined.
I mean, the guy Undefined
has only one value, which is undefined
. And any variable to which no value has been assigned has the value undefined
.
That is, by just doing let variavel;
, the variable has the value undefined
(and just to make it more confusing, there’s still one ownership of the global object called undefined
whose value is - guess - undefined
).
As for arrays, it is a little more complicated. Following explanation based in this reply by Soen.
The builder Array(n)
, when called with only one argument, and this argument is an integer, returns an array whose size (i.e., whose property value length
) is this number.
But when trying to access any of the elements of it, the return is undefined
:
let x = Array(2);
console.log(x.length); // 2
console.log(x[0], x[1]); // undefined, undefined
console.log(x);
Note: in the last line there may be divergences as to the output. Running on the site snippet, I got [undefined, undefined]
, but Chrome’s own console, the return was [empty x 2]
and on the Node was [ <2 empty items> ]
.
What happens is that, although it seems, Array(2)
is not the same thing as [undefined, undefined]
. For example, if we map each element of the array to any value, using map
:
console.log([undefined, undefined].map(e => 1)); // [1, 1]
console.log(new Array(2).map(e => 1));
On the last line, again there was the divergence: on the site snippet, the output was [undefined, undefined]
and in Chrome and Node the output was respectively [empty x 2]
and [ <2 empty items> ]
.
Finally, according to the specification, the builder Array(tamanho)
only creates an array whose property value length
is the size reported, and only. No element was actually created within it.
So by traveling it with map
the result remains "2 Empty items", as the specification says that map
checks whether the property of the array (the index, in this case) exists. But the array created with Array(tamanho)
does not possess these properties:
function verificarIndices(array) {
for (let i = 0; i < array.length; i++) {
console.log(`tem ${i}? ${array.hasOwnProperty(i)}`);
}
}
console.log('array de undefined');
verificarIndices([undefined, undefined]); // imprime "true" para os índices
console.log('Array(2)');
verificarIndices(Array(2)); // imprime "false" para os índices
console.log(Object.getOwnPropertyNames([undefined, undefined])); // ['0', '1', 'length']
console.log(Object.getOwnPropertyNames(new Array(2))); // ['length']
Which leads us to conclude that the array has no elements, and undefined
is just a value that is returned when an element does not exist. After all, this is what happens when we access an index that does not exist:
let x = [1, 2, 3];
console.log(x[999]); // undefined
Finally, another way to see the array created by Array(n)
has no indices (and therefore we can conclude that it does not have the respective elements):
console.log('percorrendo [undefined, undefined]');
for (let i in [undefined, undefined])
console.log(i); // imprime 0 e 1
console.log('percorrendo Array(2)');
for (let i in Array(2))
console.log(i); // não imprime nada
console.log('--------');
console.log(Object.keys([undefined, undefined])); // [ '0', '1' ]
console.log(Object.keys(Array(2))); // []
What about the comment on toString
, the specification says that toString
calls internally the method join
no arguments. And when join
is called without arguments, the specification says a comma is used as a separator. The algorithm also says that if the element is undefined
or null
, the empty string is used in place. And as we have seen, the access to the non-existent elements of Array(2)
returns undefined
, the result of toString
will be a bunch of commas (to be more precise, in an array of size N, will be N - 1 commas).
So for variables the
undefined
exists, but for arrays only at the moment it is accessed?– felipe cardozo
@felipecardozo In fact I believe that for objects in general, when trying to access a property that does not exist, it must have an "if (does not exist) returns Undefined" (and the indexes of an array in the background are properties of it). I didn’t find this excerpt from the specification but I’m pretty sure it should have - if I find it, update the answer
– hkotsubo
beauty :), thanks a lot!
– felipe cardozo
@felipecardozo I did not find the excerpt of the specification, but I included another example in the answer. Perhaps now it is more clear that
Array(2)
in fact only arrow the size (length
) but does not create the elements– hkotsubo
Thanks, buddy! by the effort became clearer to me.
– felipe cardozo