If I have an array having object as values at the indices like:
var a = [];
a[21] = {};
a[90] = {};
a[13] = {};
alert(a.length); // outputs 91
It's because you have a[90] as largest index so the index is starting from 0 to 90 becomes 91 in length.
And where you didn't pass the values like a[80], etc. javascript will store them as hole i.e. for eg [1, , 3, , ,90]
where commas are used indicates the hole in array.
If you try to access those values then you'll get undefined
.
That's because length gives you the next index
available in the array.
DOCS
arrayLength
If the only argument passed to the Array constructor is an integer between 0 and 2^32-1 (inclusive), this returns a new JavaScript array with length set to that number.
ECMA Specifications
Because you don't have inserted any element in the other keys than 21, 90, 13, all the remaining indexes contains undefined
. DEMO
To get actual number of elements in the array:
var a = [];
a[21] = {};
a[90] = {};
a[13] = {};
var len = 0;
for (var i = 0; i < a.length; i++) {
if (a[i] !== undefined) {
len++;
}
}
document.write(len);
Shorter version
var a = [];
a[21] = {};
a[90] = {};
a[13] = {};
for (var i = 0, len = 0; i < a.length; i++, a[i] !== undefined && len++);
document.write(len);
DEMO
EDIT
If the array contains large number of elements, looping to get its length is not the best choice.
As you've mentioned in the question, Object.keys(arr).length
is the best solution in this case, considering that you don't have any properties added on that array. Otherwise, the length
will not be what you might be expecting.(Thanks To @RobG)
Because that's the behavior of Array.length as described in the ECMAScript spec.
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.
So Array.length is always the last item's index + 1.
The array in JavaScript is a simple zero-based structure. The array.length
returns the n + 1
where n
is the maximum index in an array.
That's just how it works - when you assign 90'th element and this array's length is less than 90, it expands an array to 90 and sets the 90-th element's value. All missing values are interpreted as null
.
If you try the following code:
var a = [];
a[21] = {};
a[90] = {};
a[13] = {};
console.log(JSON.stringify(a));
You will get the following JSON:
[null,null,null,null,null,null,null,null,null,null,null,null,null,{},null,null,null,null,null,null,null,{},null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,{}]
Moreover, array.length
is not a readonly value.
If you set a length
value less than the current, then the array will be resized:
var arr = [1,2,3,4,5];
arr.length = 3;
console.log(JSON.stringify(arr));
// [1,2,3]
If you set a length
value more than the current, then the array will be expanded as well:
var arr = [1,2,3];
arr.length = 5;
console.log(JSON.stringify(arr));
// [1,2,3,null,null]
In case you need to assign such values, you can use JS objects.
You can use them as associative array and assign any key-value pairs.
var a = {};
a[21] = 'a';
a[90] = 'b';
a[13] = 'c';
a['stringkey'] = 'd';
a.stringparam = 'e'; // btw, a['stringkey'] and a.stringkey is the same
console.log(JSON.stringify(a));
// returns {"13":"c","21":"a","90":"b","stringkey":"d","stringparam":"e"}
console.log(Object.keys(a).length);
// returns 5