Why does the 1st map method below treat element #2 as undefined but the 2nd map method does not?
const a = [undefined,,42]; // Note the two consecutive commas.
console.log(a.map(x=>x)); // -> [undefined, undefined, 42]
console.log(a.map(x=>x===undefined)); // -> [true, undefined, false]
I expand on this with the code below. There I have some numbered examples illustrating my points. In each case I create a 3-element array and from then on I am only interested in the 2nd element. I show that this 2nd element can be considered to be undefined both by how it responds to .toString() (i.e. how it appears in console.log(elmt2)) as well as how it behaves in an equality statement (i.e. elmt2 === undefined?). Then, however, I map all the elements in the array to a constant string irrespective of what the values are (i.e. array.map(_=>'foo')), and look at the 2nd element of the mapped result. I would have expected all the outputs to be the constant string, but they aren't.
const check = (i, array) => {
const mapped = array.map(() => 'mapped ');
const equalsUndefined = (array[1] === undefined);
const mappable = (array.map(_=>1)[1] === 1);
console.log(`${i}: ${array[1]} ${equalsUndefined} ${mapped[1]} ${mappable}`);
};
const uExplicit = [4, undefined, 4][1];
const uEmptySlot = [4, , 4][1];
const uNewArray = (new Array(3) )[1];
console.log('#: origValue =undef? mappedValue mappable?');
check(1, [4, undefined , 4]);
check(2, [4, , 4]);
check(3, new Array(3) );
check(4, [4, uExplicit , 4]);
check(5, [4, uEmptySlot, 4]);
check(6, [4, uNewArray , 4]);
/*
results:
#: origValue =undef? mappedValue mappable?
1: undefined true mapped true
2: undefined true undefined false
3: undefined true undefined false
4: undefined true mapped true
5: undefined true mapped true
6: undefined true mapped true
*/
Line 1 shows that an explicit undefined value can be successfully mapped in this manner.
However, lines 2 & 3 show that array elements that might be considered "empty slots" cannot be successfully mapped, even though they behave as undefined according to the two tests described above. In line 2, the value is extracted from a literal empty space between two otherwise normal array elements. In line 3, the value is extracted from an array created using new Array(arrayLength).
Bizarrely, lines 3, 4 & 5 show that the values examined in lines 1, 2 & 3 respectively can be successfully mapped if they are simply assigned to a variable first, instead of being used directly.
To be clear, the MDN documentation for arrays states that new Array(arrayLength) creates "...an array of arrayLength empty slots, not slots with actual undefined values". However, the output here shows that these values are treated as undefined, at least with respect to how they behave with .toString() and in equality statements.
So, are there two different "flavours" of undefined in JavaScript, one that can be manipulated using map and one that cannot? Is this behaviour expected/blessed (even if it's perhaps somewhat counter-intuitive)? Is there a safe way to map through an array in such a way that all undefined values can be treated identically?