DEV Community

Discussion on: Kyle Simpson proved I STILL don't know JavaScript (arrays)

Collapse
 
paceaux profile image
Paceaux

You make a great argument, but I don't think it's a red herring. (I'm more than willing to be proven wrong, though).

I read your comment a few times and wondered, "If a property isn't explicitly declared, does that mean it's implicitly undefined?" i.e.... are we really saying the same thing?

I decided to dig into the specs to see if a property really is created, though. And I don't think one is.

I've found at least one spot in the ecma specs that defines this behavior in section 12.2.5:

Elided array elements are not defined.

When you say

Array properties that haven't been explicitly declared are simply not set as enumerable;

At least in this one section, it doesn't appear as though these empty slots are properties created on the array.

Most telling is step 8 of 22.1.3 of the specs that describe how an array is created:

Repeat, while k < numberOfArgsa.

a. Let Pk be ! ToString(k)
b. Let itemK be items[k
c. Let defineStatus be CreateDataProperty(array, Pk, itemK)\
d. Assert: defineStatus is true
e. Increase k by 1

So, Pk is the key, and itemK is the value. If you have an array containing an undefined, e.g. [undefined, 1, 2], it's an item ... at least I think ... according this logic.

Similarly, that would mean that in the case of [,1,2], there is no "item" in the first slot.

But that all depends on what CreateDataProperty does. When I read how CreateDataProperty behaves, in section 7.3.4, steps 3 and 4 don't give a condition for setting the enumerable prop in the descriptor to false:

  1. Let newDesc be the PropertyDescriptor { [[Value]]: V, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]:true }.
  2. Return ? O.[DefineOwnProperty]

So, if there were a value... any value, it would be enumerable. But if there isn't a value... it's not.

So I think "implicit undefined" is an accurate description of this case because the specifications dictate in at least one place that "elided array elements are not defined" ... meaning no properties are created on the array and browser implementers have to give you something if you ask for a value at a slot that has no value. So the Array internals are giving you undefined.

I think.

Collapse
 
blindfish3 profile image
Ben Calder

Like I said - this isn't something I tend to dig into too much...

But I think we're more or less in agreement - I'm just not comfortable with the idea of a distinction between explicit/implicit undefined. However you get to it undefined === undefined :D

I didn't dig into the spec but did think to do this:

var array1 = [,"a","b"];
// since an Array is just a fancy Object:
console.log(Object.keys(array1)); // ["1", "2"]
console.log(array1.hasOwnProperty(0)); // false
console.log(array1.hasOwnProperty(1)); // true
console.log(array1.hasOwnProperty(2)); // true

// seems obvious but for ... of isn't the only way to 
// get the implicit undefined
for(let i = 0; i<array1.length; i++) {
  console.log(array1[i]);
} // undefined a b

array1[0] = "c";
console.log(Object.keys(array1)); // ["0", "1", "2"]

// and just for good measure:
console.log(Object.keys([,"a",,,"b",])); // ["1", "4"]

So the above suggests that:

  • keys are only set for values that are explicitly declared
  • modern iterator functions loop over Object.keys - i.e. enumerable properties
  • for ... of assumes that Object.keys should conform to array standards (i.e. start at 0 increment by 1)
  • the old fashioned for loop just does what you tell it :)
  • undefined is always returned when you try to access an object property that doesn't exist

Thanks for the article! It turns out that thinking about what happens under the hood can consume far too much of my time :D

Thread Thread
 
paceaux profile image
Paceaux

I updated my article to reflect our conversation (seemed too useful not to)

I think this goes back to an odder quirk of JavaScript where sometimes undefined also means "undeclared", but not always.

this "implicit undefined" is really more like an "undeclared", but JavaScript doesn't provide a means to distinguish the two very easily.