How to efficiently count the number of keys/properties of an object in JavaScript

Viewed 909745

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.)

20 Answers

Here are some performance tests for three methods;

https://jsperf.com/get-the-number-of-keys-in-an-object

Object.keys().length

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;

Loop through the keys

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.

Using Map instead of Object

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.

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.

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

this works for both, Arrays and Objects

//count objects/arrays
function count(obj){
        return Object.keys(obj).length
     }

count objects/arrays and also the length of a String

function count(obj){
        if (typeof (obj) === 'string' || obj instanceof String)
        {
          return obj.length;   
        }
        return Object.keys(obj).length
     }

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.

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.

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');

I don't think this is possible (at least not without using some internals). And I don't think you would gain much by optimizing this.

Related