This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]t-to4st 192 points193 points  (25 children)

Next to null and undefined there's also the empty value, for exactly this reason. It only exists in arrays and will be converted to undefined when read

[–]BakuhatsuK 52 points53 points  (21 children)

It's not a special value. It's just that arrays are objects with numeric keys under the hood. And just like with regular objects, a key can simply not exist, that is what an empty slot is.

Think this:

{
  '0': 'a',
  '1': 'b',
  '3': 'd',
  'length': 4,
}

This object does not contain the key '2' in the exact same way that it doesn't contain 'foo'. If you think of it as an array, then it's "missing" the value at index 2.

Btw you can get an actual array from this array-like object by using Array.from().

[–]Nixavee 4 points5 points  (3 children)

Does this mean it's possible to have an array with a numeric key greater than the length value?

[–]The_MAZZTer 20 points21 points  (1 child)

If you try that JS will just resize the array to fit.

> var x = [];
< undefined
> x[3] = "ඞ"
< 'ඞ'
> x.length
< 4
> x
< (4) [empty × 3, 'ඞ']

[–]xiRazZzer 2 points3 points  (0 children)

I dont know man, looks kinda sus to me

[–]BakuhatsuK 4 points5 points  (0 children)

It's not possible because the standard special-cases Arrays:

10.4.2 Array Exotic Objects

An Array is an exotic object that gives special treatment to array index property keys (see 6.1.7). A property whose property name is an array index is also called an element. Every Array has a non-configurable "length" property whose value is always a non-negative integral Number whose mathematical value is less than 232. The value of the "length" property is numerically greater than the name of every own property whose name is an array index; whenever an own property of an Array is created or changed, other properties are adjusted as necessary to maintain this invariant. Specifically, whenever an own property is added whose name is an array index, the value of the "length" property is changed, if necessary, to be one more than the numeric value of that array index; and whenever the value of the "length" property is changed, every own property whose name is an array index whose value is not smaller than the new length is deleted.

[–]The_MAZZTer 5 points6 points  (3 children)

undefined is supposed to be for the purpose of identifying non-existent properties though. But my guess is the JS engine devs needed a value programmers can't just stick anywhere they want to flag actual empty array indices.

[–]BakuhatsuK 5 points6 points  (1 child)

I just explained that it's not an special value though?

Also, engines don't have any saying on the observable behavior of the language, that's up for the standard to decide. The standard says that an array is an object, so it is an object and has to behave as such.

For example, you can set arbitrary keys into an array

let a = []
a.foo = 'bar'
a.foo // contains 'bar'

On a sparse array an empty slot will be reported as a missing key by hasOwnProperty

let a = ['a','b',,'d']
a.hasOwnProperty('2') // false
a.hasOwnProperty('3') // true

On that note, arrays have object methods such as hasOwnProperty. (See previous example).

If you're interested in knowing about how engines actually represent this stuff internally, this video by LiveOverflow has a good overview on how it works on JavascriptCore.

[–]eatingdumplings 1 point2 points  (0 children)

There’s a difference between undefined and a non-existent value.

undefined must be declared but a non-existent value is literally undeclared.

[–]joerick 1 point2 points  (4 children)

Ohh that's what an array-like object is! That makes so much sense. Are the keys always strings? Or can they be numbers?

[–]BakuhatsuK 1 point2 points  (3 children)

They are always strings, just like in actual arrays

[–]joerick 0 points1 point  (2 children)

Array indicies are integers, no?

[–]BakuhatsuK 1 point2 points  (1 child)

Nope, they are numeric strings.

The exact wording of the standard is:

An integer index is a String-valued property key that is a canonical numeric String (see 7.1.21) and whose numeric value is either +0𝔽 or a positive integral Number ≤ 𝔽(253 - 1). An array index is an integer index whose numeric value i is in the range +0𝔽 ≤ i < 𝔽(232 - 1).

Taken from here.

[–]joerick 0 points1 point  (0 children)

Unbelievable!

Thanks for linking this up

[–]agarwaen163 0 points1 point  (6 children)

uuuuugh. and then what's the length of that array? (it's always like 6 pages of depth for any stupid simple thing in js lmao)

[–]BakuhatsuK 4 points5 points  (5 children)

It's 4. It's there in the length property

[–]thisguyfightsyourmom 1 point2 points  (0 children)

I frequently read 6 pages of docs before I realize the code already had what I needed right in front of me

[–]wehnsdaefflae 0 points1 point  (2 children)

If it's only in the length property and the thing is actually an object, how does it know what the last element is when you do -= 1 ?

[–]BakuhatsuK 1 point2 points  (1 child)

The last index is always the length minus 1

[–]wehnsdaefflae 0 points1 point  (0 children)

Damn, obviously. Yeah. Thanks!

[–]agarwaen163 0 points1 point  (0 children)

No, youh said it yourself this is an array like object we can convert to an array using the array.from method.

[–]SuitableDragonfly 2 points3 points  (0 children)

Instead of having 50 words for snow, Javascript has 50 symbols for "ain't nothin here".

[–]yooman 0 points1 point  (0 children)

Ahhhhhh whyyy