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.)
19 Answers 19
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
- Browser compatibility
- Object.keys documentation (includes a method you can add to non-ES5 browsers)
-
9Not just Node.js, but any environment that supports ES5Yi Jiang– Yi Jiang04/03/2011 23:38:51Commented Apr 3, 2011 at 23:38
-
71BTW... just ran some tests... this method runs in O(n) time. A for loop isn't much worse than this method. ** sad face ** stackoverflow.com/questions/7956554/…BMiner– BMiner10/31/2011 16:58:22Commented Oct 31, 2011 at 16:58
-
209-1 (-200 if I could) This not only iterates through the object but also creates a whole new array with all its keys, so it completely fails at answering the question.GetFree– GetFree06/22/2012 14:28:10Commented Jun 22, 2012 at 14:28
-
47It seems much faster than doing the for (at least on Chrome 25): jsperf.com/count-elements-in-objectfserb– fserb11/18/2012 15:51:51Commented Nov 18, 2012 at 15:51
-
59@GetFree Why so many thumbs up? This is definitely the fastest way in terms of coding. No extra methods or libraries required. In terms of code speed, apparently it's not too bad either. Not a complete fail at all.Andrew– Andrew06/02/2016 17:31:58Commented Jun 2, 2016 at 17:31
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;
-
4What is the purpose of the check
(Object.prototype.hasOwnProperty.call(obj, k))
?styfle– styfle05/14/2012 21:04:57Commented May 14, 2012 at 21:04 -
16@styfle If you use a for loop to iterate over the object's properties, you also get the properties in the prototype chain. That's why checking
hasOwnProperty
is necessary. It only returns properties set on the object itself.Renaat De Muynck– Renaat De Muynck05/21/2012 09:44:28Commented May 21, 2012 at 9:44 -
15@styfle To make it simpler you could just write
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 theObject
's prototype, but in the rare event that this method would be removed or overridden you might get unexpected results. By calling it fromObject.prototype
it makes it little more robust. The reason for usingcall
is because you want to invoke the method onobj
instead of on the prototype.Renaat De Muynck– Renaat De Muynck05/23/2012 20:59:10Commented May 23, 2012 at 20:59 -
6Would not it better to use this version ? developer.mozilla.org/en-US/docs/JavaScript/Reference/…Xavier Delamotte– Xavier Delamotte01/23/2013 14:28:48Commented Jan 23, 2013 at 14:28
-
1@XavierDelamotte You are absolutely correct. While my version works, it is very basic and ment as an example. Mozilla's code is more safe. (PS: Your link is also in the accepted answer)Renaat De Muynck– Renaat De Muynck01/30/2013 17:39:13Commented Jan 30, 2013 at 17:39
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.
-
9If you use underscore.js then you should use _.size instead. The good thing is that if you somehow switch from array to object or vice versa the result stays the same.douwe– douwe06/20/2011 11:18:30Commented Jun 20, 2011 at 11:18
-
2And from my understanding lodash is generally better than underscore (though they do similar things).Merlyn Morgan-Graham– Merlyn Morgan-Graham08/02/2015 23:24:49Commented Aug 2, 2015 at 23:24
-
1@MerlynMorgan-Graham if I recall correctly, lodash is originally a fork of underscore...molson504x– molson504x08/19/2015 12:18:48Commented Aug 19, 2015 at 12:18
-
6
_.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.Jacob Stamm– Jacob Stamm11/23/2015 23:02:40Commented Nov 23, 2015 at 23:02 -
2O(n) complexity. Lodash and Underscore use
Object.keys
internally. Underscore also copies every key into an array inside afor..in
loop ifObject.keys
is not defined.N. Kudryavtsev– N. Kudryavtsev03/22/2019 13:32:28Commented Mar 22, 2019 at 13:32
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
Object.keys 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.
-
30"Using Map instead of Object" - this is the most helpful suggestion on this page.Roy Tinker– Roy Tinker09/02/2021 22:16:23Commented Sep 2, 2021 at 22:16
-
MDN has a useful comparison of
Object
vs.Map
: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…. The downside seems to be lack of native support forJSON.stringify
andJSON.parse
. Wrappers end up convertingMap
->Object
forJSON
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.OXiGEN– OXiGEN02/24/2023 07:58:31Commented Feb 24, 2023 at 7:58 -
Sadly, looks like jsperf is down. Is there any chance, if it comes back up again, someone could edit the benchmark code into the answer? I tried to reproduce on another site (jsbench.me, though without a login, I can't share the tests), testing with a single fixed object with 26 keys, for lowercase
a
throughz
, 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 usinghasOwnProperty
(cached or uncached, branching or not).ShadowRanger– ShadowRanger06/02/2023 17:54:20Commented Jun 2, 2023 at 17:54 -
Using a
Map
instead was in turn nearly twice the throughput of theObject.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 thefor
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 theMap
solution areO(n)
).ShadowRanger– ShadowRanger06/02/2023 18:03:36Commented Jun 2, 2023 at 18:03 -
You should provide measurements for different nuser877329– user87732907/16/2023 12:24:40Commented Jul 16, 2023 at 12:24
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:
1. ECMAScript's Object.keys()
Object.keys(obj).length;
Works by internally iterating over the keys to compute a temporary array and returns its length.
- Pros - Readable and clean syntax. No library or custom code required except a shim if native support is unavailable
- Cons - Memory overhead due to the creation of the array.
2. Library-based solutions
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).
3. Optimizing a for-loop
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.
-
Why would
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?Lars Gyrup Brink Nielsen– Lars Gyrup Brink Nielsen03/05/2014 08:58:27Commented Mar 5, 2014 at 8:58 -
1Is this faster?
for (var k in myobj) hasOwn.call(myobj, k) && ++count;
i.e. replacing the if statement with a simple &&?Hamza Kubba– Hamza Kubba04/20/2014 21:30:37Commented Apr 20, 2014 at 21:30 -
1Last thing you can do with:
Object.getOwnPropertyNames(obj).length
; much simpler.Wilt– Wilt02/27/2020 16:29:50Commented Feb 27, 2020 at 16:29 -
@HamzaKubba: That would be logically exactly equivalent; I doubt any JS engine would optimize either of them differently. It's very slightly possible that
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 tocount
even when it's not an own-prop matter. But at least in testing on Edge 113, it's slightly slower with+=
.ShadowRanger– ShadowRanger06/02/2023 18:06:42Commented Jun 2, 2023 at 18:06 -
And just for my own edification,
hasOwn.call(myobj, k) && ++count
was slightly slower thanif (hasOwn.call(myobj, k)) ++count
. A trivial difference (and could easily be timing jitter), but it's definitely not better.ShadowRanger– ShadowRanger06/02/2023 18:11:01Commented Jun 2, 2023 at 18:11
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.
-
6@hitautodestruct Because he offers a solution.crush– crush02/10/2013 21:12:26Commented Feb 10, 2013 at 21:12
-
@crush This answer seems to suggest things to do rather than give a direct solution.hitautodestruct– hitautodestruct02/11/2013 06:40:58Commented Feb 11, 2013 at 6:40
-
6@hitautodestruct it suggests an answer: incrementing/decrementing an encapsulated count with the add/remove methods. There is another answer exactly like this below. The only difference is, Confusion did not offer any code. Answers are not mandated to provide code solutions only.crush– crush02/11/2013 14:25:09Commented Feb 11, 2013 at 14:25
-
2it may not be perfect ... but compared with the other "answers" this may be the best solution for some situationsd.raev– d.raev07/22/2016 12:46:19Commented Jul 22, 2016 at 12:46
-
2So far this is the only solution I see that is O(1) constant time performance complexity, and therefore is the only solution that Answers the Question detail of "without iterating" and should therefore be the tru Accepted Answer. Most if not all other answers don't answer that, because they offer an O(n) linear time performance complexity; that's the case also for the 1-line solutions that call something like a .keys() function, as such function calls are O(n).cellepo– cellepo05/30/2018 17:38:30Commented May 30, 2018 at 17:38
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
-
1What answer in particular? Can you link to it (normal linking, not a naked link)?Peter Mortensen– Peter Mortensen07/22/2021 19:37:18Commented Jul 22, 2021 at 19:37
-
1I was just referring to
Object.keys(obj).length
stackoverflow.com/a/4889658/532695Flavien Volken– Flavien Volken07/23/2021 00:15:12Commented Jul 23, 2021 at 0:15
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
}
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 ;)
-
2Thumbs up for mentioning
Object.getOwnPropertyNames
, you were the only one here...Wilt– Wilt02/27/2020 16:31:12Commented Feb 27, 2020 at 16:31
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)
-
In response to your comments about
Array(obj).length
: It doesn't work. http://jsfiddle.net/Jhy8M/Jamie Chong– Jamie Chong04/10/2014 00:06:51Commented Apr 10, 2014 at 0:06 -
yeah i looked into it a bit more im going to end up removing this answer if possible or just editing it all togetherBelldandu– Belldandu05/22/2014 15:28:37Commented May 22, 2014 at 15:28
-
1I'm not seeing that this has anything to do with functions, for one, and in Chrome I don't see this behavior at all. I would suspect this may have had to do with the default behavior of Object.defineProperty():enumerable which is
false
, though I've not yet found any documentation on howvar obj = { a: true, b: true }
may differ fromvar obj = {}; obj.a = true; obj.b = true;
or simply if a different interpretation/semantics of the W3 has been adopted by Chrome.Nolo– Nolo10/02/2016 08:06:16Commented Oct 2, 2016 at 8:06
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.
-
13Note that
Object.prototype.__count__
is being removed in Gecko 1.9.3: whereswalden.com/2010/04/06/… count-property-of-objects-is-being-removed/dshaw– dshaw04/20/2010 16:27:04Commented Apr 20, 2010 at 16:27 -
17Now that Firefox 4 is out, this answer is now obsolete.
Object.__count__
is gone, and good riddance too.Yi Jiang– Yi Jiang04/03/2011 23:50:54Commented Apr 3, 2011 at 23:50 -
1I wouldn't say the answer is obsolete. It's still an interesting strategy to encapsulate a value in a function.devios1– devios107/12/2011 13:30:31Commented Jul 12, 2011 at 13:30
-
should be using the prototype object to extendAaria Carter-Weir– Aaria Carter-Weir09/01/2011 08:25:54Commented Sep 1, 2011 at 8:25
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 = "[email protected]";
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: [email protected]
Note: it does not work in browsers before Internet Explorer 9.
-
2If you’re going to extend built-in prototypes or polyfill a property (i.e. monkey-patch), please do it correctly: for forward compatibility, check if the property exists first, then make the property non-enumerable so that the own keys of constructed objects aren’t polluted. For methods use actual methods. My recommendation: follow these examples which demonstrate how to add a method that behaves as closely as possible like built-in methods.Sebastian Simon– Sebastian Simon05/09/2020 09:52:09Commented May 9, 2020 at 9:52
For those who have Underscore.js included in their project you can do:
_({a:'', b:''}).size() // => 2
or functional style:
_.size({a:'', b:''}) // => 2
-
1The question was not about other methods, but the fastest method. You propose using library, which already by itself fails in performance.vanowm– vanowm03/14/2021 02:31:27Commented Mar 14, 2021 at 2:31
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];
}
}
-
1Interesting alternative. This does eliminate the overhead of an aggregate counting function, but at the cost of a function call every time you add or remove an element, which unfortunately may be worse. I'd personnaly use such a list implementation for the data encapsulation and custom methods it can provide compared to a plain array, but not when I just need fast item counting.Luc125– Luc12505/26/2013 19:11:26Commented May 26, 2013 at 19:11
-
1I like your answer, but I also am a lemming and clicked upvote. This presents an interesting dilemma. You're not accounting for some behavior in your instructions, such as my situation where I've already upvoted your answer, but then I am instructed to "click upvote" and cannot. The instruction fails silently but I gather from your content here on SO that failing silently is not something you like your code doing. Just a heads up.L0j1k– L0j1k12/01/2013 04:10:29Commented Dec 1, 2013 at 4:10
-
1I really like this answer, nice data structure. And if there was a performance impact with the function calls on add, there would be a far greater performance boost if having to iterate over an object. This should allow for the fastest loop patten
var i = basiclist.count
while(i--){...}
Lex– Lex03/27/2014 22:42:20Commented Mar 27, 2014 at 22:42 -
Shouldn't a basic list at least include basic checks? Like checking if
add
replaces an old item or ifremove
is called with a non-existing index. Also it's not possible to check if the list has a given index ifundefined
is a valid item value.Robert– Robert06/23/2014 13:39:07Commented Jun 23, 2014 at 13:39 -
2A list should be ordered and iterable. Data is stored in an object so there's no guarantee on the ordering of elements. How do you find the length a list with holes in it? this.count? The highest index value? If you ever add two items at the same index the count goes into an error state.Ultimate Gobblement– Ultimate Gobblement11/19/2014 10:30:59Commented Nov 19, 2014 at 10:30
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.
You can use:
Object.keys(objectName).length;
and
Object.values(objectName).length;
Test
const person = {
firstName: 'John',
lastName: 'Doe'
};
console.log(
Object.keys(person).length,
Object.values(person).length,
Object.entries(person).length
)
-
1From looking at all the other answers, the important part of the question was tthe "efficiently" bit.Moritz Ringler– Moritz Ringler05/11/2023 23:49:51Commented May 11, 2023 at 23:49
If jQuery in previous answers does not work, then try
$(Object.Item).length
-
4It seems that
Object.Item
does not existLuc125– Luc12505/26/2013 18:55:26Commented May 26, 2013 at 18:55 -
What answer(s) in particular? Can you link to some or all of them?Peter Mortensen– Peter Mortensen07/22/2021 19:46:18Commented Jul 22, 2021 at 19:46
-
OK, user codejoecode has left the building. Perhaps somebody else?Peter Mortensen– Peter Mortensen07/22/2021 19:46:56Commented Jul 22, 2021 at 19:46
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
-
1Modifying objects you don't own is a bad idea.jens1101– jens110111/16/2021 07:18:54Commented Nov 16, 2021 at 7:18
Explore related questions
See similar questions with these tags.
Map
.