var arr = [\"He
This happens because length
is only updated when a new numeric property is added to the array as required by the specification:
The length property of this Array object is a data property whose value is always numerically greater than the name of every deletable property whose name is an array index.
And an array index is specified to be:
A property name P (in the form of a String value) is an array index if and only if ToString(ToUint32(P)) is equal to P and ToUint32(P) is not equal to 232−1.
However, arrays are also objects - so you can add non-array-index properties to an array, just like you can add properties to any other JavaScript object (which is why your example doesn't throw either).
javascript length is calculated as 1+(highest numeric index element). so when you add arr['Hello']
, you are only adding a string index which is not taken into account when calculating the array length.
This is the actual definition of the array length property as described in ECMAScript 5.1:
Every Array object has a length property whose value is always a nonnegative integer less than 232. The value of the length property is numerically greater than the name of every property whose name is an array index; whenever a property of an Array object is created or changed, other properties are adjusted as necessary to maintain this invariant. Specifically, whenever a property is added whose name is an array index, the length property is changed, if necessary, to be one more than the numeric value of that array index; and whenever the length property is changed, every property whose name is an array index whose value is not smaller than the new length is automatically deleted. This constraint applies only to own properties of an Array object and is unaffected by length or array index properties that may be inherited from its prototypes.
When you write:
arr["Hello"]=...
you are creating a new Object associated with the arr
Array object, which does not affect the length of arr
.
You can achieve the same effect by writing:
arr.Hello=...
Quoting ECMA Script 5 Specification of Array Objects,
A property name
P
(in the form of a String value) is an array index if and only ifToString(ToUint32(P))
is equal toP
andToUint32(P)
is not equal to 232−1.
Since Hello
is not valid, according to the above definition, it is not considered as an array index but just as an ordinary property.
Quoting MDN's Relationship between length and numerical properties section,
When setting a property on a JavaScript array when the property is a valid array index and that index is outside the current bounds of the array, the engine will update the array's length property accordingly
So, only if the property is a valid array index, the length
property will be adjusted.
In your case, you have just created a new property Hello
on the array object.
Note: Only the numerical properties will be used in all of the Array
's prototype functions, like forEach
, map
, etc.
For example, the array shown in question, when used with forEach
,
arr.forEach(function(currentItem, index) {
console.log(currentItem, index);
})
would print
Hello 0
There 1
123 2
456 3
{ show: [Function] } 4
even though the list of keys shows Hello
.
console.log(Object.keys(arr));
// [ '0', '1', '2', '3', '4', 'Hello' ]
It is because, Array
is derived from Object
,
console.log(arr instanceof Object);
// true
and Hello
is a valid key of the array object, but just not a valid array index. So, when you treat the array as an Object, Hello
will be included in the keys, but the array specific functions will include only the numerical properties.