What's the fastest way to count the number of keys/properties of an object? Is it possible to do this without iterating over the object? I.e., without doing:
var count = 0;
for (k in myobj) if (myobj.hasOwnProperty(k)) ++count;
(Firefox did provide a magic __count__
property, but this was removed somewhere around version 4.)
Map
. - anyone To do this in any ES5-compatible environment, such as Node.js, Chrome, Internet Explorer 9+, Firefox 4+, or Safari 5+:
Object.keys(obj).length
Answered 2023-09-21 08:06:53
You could use this code:
if (!Object.keys) {
Object.keys = function (obj) {
var keys = [],
k;
for (k in obj) {
if (Object.prototype.hasOwnProperty.call(obj, k)) {
keys.push(k);
}
}
return keys;
};
}
Then you can use this in older browsers as well:
var len = Object.keys(obj).length;
Answered 2023-09-21 08:06:53
(Object.prototype.hasOwnProperty.call(obj, k))
? - anyone hasOwnProperty
is necessary. It only returns properties set on the object itself. - anyone obj.hasOwnProperty(k)
(I actually did this in my original post, but updated it later). hasOwnProperty
is available on every object because it is part of the Object
's prototype, but in the rare event that this method would be removed or overridden you might get unexpected results. By calling it from Object.prototype
it makes it little more robust. The reason for using call
is because you want to invoke the method on obj
instead of on the prototype. - anyone If you are using Underscore.js you can use _.size (thanks douwe):
_.size(obj)
Alternatively you can also use _.keys which might be clearer for some:
_.keys(obj).length
I highly recommend Underscore.js. It's a tight library for doing lots of basic things. Whenever possible, they match ECMAScript 5 and defer to the native implementation.
Otherwise I support Avi Flax' answer. I edited it to add a link to the MDC documentation which includes the keys() method you can add to non-ECMAScript 5 browsers.
Answered 2023-09-21 08:06:53
_.keys(obj).length
worked best for me, because my return object is sometimes a plain string with no properties within it. _.size(obj)
gives me back the length of the string, while _.keys(obj).length
returns 0. - anyone Object.keys
internally. Underscore also copies every key into an array inside a for..in
loop if Object.keys
is not defined. - anyone The standard Object implementation (ES5.1 Object Internal Properties and Methods) does not require an Object
to track its number of keys/properties, so there should be no standard way to determine the size of an Object
without explicitly or implicitly iterating over its keys.
So here are the most commonly used alternatives:
Object.keys(obj).length;
Works by internally iterating over the keys to compute a temporary array and returns its length.
Many library-based examples elsewhere in this topic are useful idioms in the context of their library. From a performance viewpoint, however, there is nothing to gain compared to a perfect no-library code since all those library methods actually encapsulate either a for-loop or ES5 Object.keys
(native or shimmed).
The slowest part of such a for-loop is generally the .hasOwnProperty()
call, because of the function call overhead. So when I just want the number of entries of a JSON object, I just skip the .hasOwnProperty()
call if I know that no code did nor will extend Object.prototype
.
Otherwise, your code could be very slightly optimized by making k
local (var k
) and by using prefix-increment operator (++count
) instead of postfix.
var count = 0;
for (var k in myobj) if (myobj.hasOwnProperty(k)) ++count;
Another idea relies on caching the hasOwnProperty
method:
var hasOwn = Object.prototype.hasOwnProperty;
var count = 0;
for (var k in myobj) if (hasOwn.call(myobj, k)) ++count;
Whether this is faster or not on a given environment is a question of benchmarking. Very limited performance gain can be expected anyway.
Answered 2023-09-21 08:06:53
var k in myobj
boost performance? As far as I know, only functions declare new scope in JavaScript. Are in-loops an exception to this rule? - anyone for (var k in myobj) hasOwn.call(myobj, k) && ++count;
i.e. replacing the if statement with a simple &&? - anyone Object.getOwnPropertyNames(obj).length
; much simpler. - anyone for (var k in myobj) count += myobj.hasOwnProperty(k);
might do better, as it would be replacing a logical test-and-branch with branch-free (in the sense of unpredictable branches) code, but that all depends on whether the engine pays any price to convert from bool to int and whether unconditional writes to count
even when it's not an own-prop matter. But at least in testing on Edge 113, it's slightly slower with +=
. - anyone hasOwn.call(myobj, k) && ++count
was slightly slower than if (hasOwn.call(myobj, k)) ++count
. A trivial difference (and could easily be timing jitter), but it's definitely not better. - anyone Here are some performance tests for three methods;
https://jsperf.com/get-the-number-of-keys-in-an-object
20,735 operations per second
It is very simple and compatible and runs fast but expensive, because it creates a new array of keys, which then gets thrown away.
return Object.keys(objectToRead).length;
15,734 operations per second
let size=0;
for(let k in objectToRead) {
size++
}
return size;
It is slightly slower, but nowhere near the memory usage, so it is probably better if you're interested in optimising for mobile or other small machines.
953,839,338 operations per second
return mapToRead.size;
Basically, Map tracks its own size, so we're just returning a number field. It is far, far faster than any other method. If you have control of the object, convert them to maps instead.
Answered 2023-09-21 08:06:53
Object
vs. Map
: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…. The downside seems to be lack of native support for JSON.stringify
and JSON.parse
. Wrappers end up converting Map
-> Object
for JSON
functions, so it kind of defeats the purpose for content that only exists to be serialized/deserialized. If serialization and actual Object functionality are not needed, Map
appears to be the superior choice. - anyone a
through z
, and, on Edge 113, running on a thin client setup (so the work was done on pretty beefy, but shared, servers), Object.keys().length
had throughput over 5x greater than the for loop, and over 10x any for loop variant using hasOwnProperty
(cached or uncached, branching or not). - anyone Map
instead was in turn nearly twice the throughput of the Object.keys().length
solution, so the rankings were unchanged, but the degree of success was quite different; Map
was better, but only around 2x, not 50x better. Object.keys().length
was twice as good as the for
loop, not just a third higher throughput. But of course, my microbenchmark (reusing the same object/Map
over and over) may allow JS engines to optimize when they shouldn't, and the relative performance would obviously depend on the size of the object/Map
(since all but the Map
solution are O(n)
). - anyone If you are actually running into a performance problem I would suggest wrapping the calls that add/remove properties to/from the object with a function that also increments/decrements an appropriately named (size?) property.
You only need to calculate the initial number of properties once and move on from there. If there isn't an actual performance problem, don't bother. Just wrap that bit of code in a function getNumberOfProperties(object)
and be done with it.
Answered 2023-09-21 08:06:53
As answered in a previous answer: Object.keys(obj).length
But: as we have now a real Map class in ES6, I would suggest to use it instead of using the properties of an object.
const map = new Map();
map.set("key", "value");
map.size; // THE fastest way
Answered 2023-09-21 08:06:53
Object.keys(obj).length
stackoverflow.com/a/4889658/532695 - anyone this works for both, Arrays and Objects
//count objects/arrays
function count(obj){
return Object.keys(obj).length
}
count objects/arrays with a Loop
function count(obj){
var x=0;
for(k in obj){
x++;
}
return x;
}
count objects/arrays or also the length of a String
function count(obj){
if (typeof (obj) === 'string' || obj instanceof String)
{
return obj.toString().length;
}
return Object.keys(obj).length
}
Answered 2023-09-21 08:06:53
Object.keys(obj).length
will do the trick for all enumerable properties on your object, but to also include the non-enumerable properties, you can instead use the Object.getOwnPropertyNames
. Here's the difference:
var myObject = new Object();
Object.defineProperty(myObject, "nonEnumerableProp", {
enumerable: false
});
Object.defineProperty(myObject, "enumerableProp", {
enumerable: true
});
console.log(Object.getOwnPropertyNames(myObject).length); //outputs 2
console.log(Object.keys(myObject).length); //outputs 1
console.log(myObject.hasOwnProperty("nonEnumerableProp")); //outputs true
console.log(myObject.hasOwnProperty("enumerableProp")); //outputs true
console.log("nonEnumerableProp" in myObject); //outputs true
console.log("enumerableProp" in myObject); //outputs true
As stated here, this has the same browser support as Object.keys
.
However, in most cases, you might not want to include the nonenumerables in these type of operations, but it's always good to know the difference ;)
Answered 2023-09-21 08:06:53
Object.getOwnPropertyNames
, you were the only one here... - anyone To iterate on Avi Flax' answer, Object.keys(obj).length is correct for an object that doesn’t have functions tied to it.
Example:
obj = {"lol": "what", owo: "pfft"};
Object.keys(obj).length; // should be 2
versus
arr = [];
obj = {"lol": "what", owo: "pfft"};
obj.omg = function(){
_.each(obj, function(a){
arr.push(a);
});
};
Object.keys(obj).length; // should be 3 because it looks like this
/* obj === {"lol": "what", owo: "pfft", omg: function(){_.each(obj, function(a){arr.push(a);});}} */
Steps to avoid this:
do not put functions in an object that you want to count the number of keys in
use a separate object or make a new object specifically for functions (if you want to count how many functions there are in the file using Object.keys(obj).length
)
Also, yes, I used the _
or Underscore.js module from Node.js in my example.
Documentation can be found here as well as its source on GitHub and various other information.
And finally a lodash implementation https://lodash.com/docs#size
_.size(obj)
Answered 2023-09-21 08:06:53
Array(obj).length
: It doesn't work. http://jsfiddle.net/Jhy8M/ - anyone false
, though I've not yet found any documentation on how var obj = { a: true, b: true }
may differ from var obj = {}; obj.a = true; obj.b = true;
or simply if a different interpretation/semantics of the W3 has been adopted by Chrome. - anyone I'm not aware of any way to do this. However, to keep the iterations to a minimum, you could try checking for the existence of __count__
and if it doesn't exist (i.e., not Firefox) then you could iterate over the object and define it for later use, e.g.:
if (myobj.__count__ === undefined) {
myobj.__count__ = ...
}
This way, any browser supporting __count__
would use that, and iterations would only be carried out for those which don't. If the count changes and you can't do this, you could always make it a function:
if (myobj.__count__ === undefined) {
myobj.__count__ = function() { return ... }
myobj.__count__.toString = function() { return this(); }
}
This way, any time you reference myobj.__count__
the function will fire and recalculate.
Answered 2023-09-21 08:06:53
Object.prototype.__count__
is being removed in Gecko 1.9.3: whereswalden.com/2010/04/06/…count-property-of-objects-is-being-removed/ - anyone Object.__count__
is gone, and good riddance too. - anyone From Object.defineProperty():
Object.defineProperty(obj, prop, descriptor)
You can either add it to all your objects:
Object.defineProperty(Object.prototype, "length", {
enumerable: false,
get: function() {
return Object.keys(this).length;
}
});
Or a single object:
var myObj = {};
Object.defineProperty(myObj, "length", {
enumerable: false,
get: function() {
return Object.keys(this).length;
}
});
Example:
var myObj = {};
myObj.name = "John Doe";
myObj.email = "leaked@example.com";
myObj.length; // Output: 2
Added that way, it won't be displayed in for..in loops:
for(var i in myObj) {
console.log(i + ": " + myObj[i]);
}
Output:
name: John Doe
email: leaked@example.com
Note: it does not work in browsers before Internet Explorer 9.
Answered 2023-09-21 08:06:53
For those who have Underscore.js included in their project you can do:
_({a:'', b:''}).size() // => 2
or functional style:
_.size({a:'', b:''}) // => 2
Answered 2023-09-21 08:06:53
How I've solved this problem is to build my own implementation of a basic list which keeps a record of how many items are stored in the object. It’s very simple. Something like this:
function BasicList()
{
var items = {};
this.count = 0;
this.add = function(index, item)
{
items[index] = item;
this.count++;
}
this.remove = function (index)
{
delete items[index];
this.count--;
}
this.get = function(index)
{
if (undefined === index)
return items;
else
return items[index];
}
}
Answered 2023-09-21 08:06:53
var i = basiclist.count
while(i--){...}
- anyone add
replaces an old item or if remove
is called with a non-existing index. Also it's not possible to check if the list has a given index if undefined
is a valid item value. - anyone For those that have Ext JS 4 in their project, you can do:
Ext.Object.getSize(myobj);
The advantage of this is that it'll work on all Ext JS compatible browsers (Internet Explorer 6 - Internet Explorer 8 included). However, I believe the running time is no better than O(n) though, as with other suggested solutions.
Answered 2023-09-21 08:06:53
You can use:
Object.keys(objectName).length;
and
Object.values(objectName).length;
Answered 2023-09-21 08:06:53
Test
const person = {
firstName: 'John',
lastName: 'Doe'
};
console.log(
Object.keys(person).length,
Object.values(person).length,
Object.entries(person).length
)
Answered 2023-09-21 08:06:53
The OP didn't specify if the object is a nodeList. If it is, then you can just use the length method on it directly. Example:
buttons = document.querySelectorAll('[id=button)) {
console.log('Found ' + buttons.length + ' on the screen');
Answered 2023-09-21 08:06:53
If jQuery in previous answers does not work, then try
$(Object.Item).length
Answered 2023-09-21 08:06:53
Object.Item
does not exist - anyone I try to make it available to all objects like this:
Object.defineProperty(Object.prototype,
"length",
{
get() {
if (!Object.keys) {
Object.keys = function (obj) {
var keys = [],k;
for (k in obj) {
if (Object.prototype.hasOwnProperty.call(obj, k)) {
keys.push(k);
}
}
return keys;
};
}
return Object.keys(this).length;
},});
console.log({"Name":"Joe", "Age":26}.length) // Returns 2
Answered 2023-09-21 08:06:53