How to get number of properties in an Object
without the performance penalty that is associated with Object.keys().length
?
Asked
Active
Viewed 2,914 times
1

exebook
- 32,014
- 33
- 141
- 226
-
Possible duplicate of [Length of a JavaScript object (that is, associative array)](http://stackoverflow.com/q/5223/1529630) – Oriol May 23 '16 at 03:30
-
2you don't, but `Object.keys` is very fast anyway – dandavis May 23 '16 at 03:30
-
Possible duplicate of [How to efficiently count the number of keys/properties of an object in JavaScript?](http://stackoverflow.com/questions/126100/how-to-efficiently-count-the-number-of-keys-properties-of-an-object-in-javascrip) – Paarth May 23 '16 at 03:31
-
See [this community wiki answer in particular](http://stackoverflow.com/a/16763915/2557260) – Paarth May 23 '16 at 03:31
-
3out of curiosity, what "performance penalty" are you speaking of? – dandavis May 23 '16 at 03:33
-
@dandavis Allocating an array with all property names, I guess. – Oriol May 23 '16 at 03:36
-
You're better off describing what your measured performance problem is and asking a question about that. If you haven't measured this as a performance problem, it probably isn't. – pvg May 23 '16 at 03:37
-
`Object.keys().length` returns results in briefer span than `JSON.stringify()` – guest271314 May 23 '16 at 03:37
-
1@guest271314 How exactly do you use `JSON.stringify()` to count properties? – Oriol May 23 '16 at 03:44
-
@Oriol Define `var n = 0` outside of `JSON.stringify()`, increment `++n` at each occurence of a property within replacer function – guest271314 May 23 '16 at 03:45
-
@guest271314 OK, you are right. Here is an even slower approach: `var d = new Date().getTime() + 1e4; while(new Date() < d); Object.keys(myObj).length`. – Oriol May 23 '16 at 03:51
-
@Oriol _"Here is an even slower approach:"_ Not following? – guest271314 May 23 '16 at 03:55
-
making an array that's thrown-away imposes more of a RAM penalty than a performance penalty. – dandavis May 23 '16 at 04:50
3 Answers
2
You could do a for-in loop, it's pretty fast. Basically it iterates through all the keys in the object and increments the counter for each one. Based on a quick benchmark in my console, it's about 5 times faster than Object.keys().length
var counter = 0;
for(var i in obj){
counter++;
}

Joe Thomas
- 5,807
- 6
- 25
- 36
0
You can switch to Map, which is similar to Object, but also you can get size of it, and iterate through keys. It is supported by many browsers, and for older ones there are polyfills.

amaksr
- 7,555
- 2
- 16
- 17
-
While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes – Joe Thomas May 23 '16 at 03:48
0
If you want a fast approach, basically you have two possibilities:
Keep track of the size of your object manually. Store the size in a variable, increase it when creating a property, and decrease it when deleting.
var myObj = {}, size = 0; myObj.foo = 1; ++size; myObj.bar = 2; ++size; size; // 2
Use a similar data structure which exposes the size. For example, ES6 maps.
var myMap = new Map(); myMap.set("foo", 1); myMap.set("bar", 2); myMap.size; // 2

Oriol
- 274,082
- 63
- 437
- 513
-
in that code, it seems using Map() isn't actually any faster than using a plain object and running Object.keys(). i realize it's a stub, but would you expect `Map` to be faster on a larger collection? – dandavis May 23 '16 at 03:39
-
@dandavis I don't only expect it. It *must* be faster. Map operations are required to be sublinear (on average) with the size of the map, `Object.keys` is linear (unless it has been cached or something). – Oriol May 23 '16 at 03:40
-
@Oriel: why do these result seemingly contradict what you say "must be faster": http://pagedemos.com/84xj3qxfm7cz/2 ? i ran them a bunch and i never saw a Map outperform an Object... i trust you (a lot), but i like to verify ;) – dandavis May 23 '16 at 03:48
-
@dandavis I think the test should be more [like this](http://pagedemos.com/84xj3qxfm7cz/3). Map: 0.1, Obj: 2150. The advantage of maps is noticeable when the size is huge. – Oriol May 23 '16 at 04:03
-
Object.keys should be taking longer as according to the spec [size is a getter](http://www.ecma-international.org/ecma-262/6.0/#sec-get-map.prototype.size) that loops the List entries and returning a count. [Object.keys](http://www.ecma-international.org/ecma-262/6.0/#sec-object.keys) however does two loops: one in [EnumerableOwnNames](http://www.ecma-international.org/ecma-262/6.0/#sec-enumerableownnames) and then one in [CreateArrayFromList](http://www.ecma-international.org/ecma-262/6.0/#sec-createarrayfromlist) of course speed also depends on the vendors implementation – Patrick Evans May 23 '16 at 04:07
-
@Oriol Is there an infinite loop at `js` at linked page http://pagedemos.com/84xj3qxfm7cz/3? – guest271314 May 23 '16 at 04:09
-
@PatrickEvans See [Map Objects](http://www.ecma-international.org/ecma-262/6.0/#sec-map-objects): "Map object must be implemented using either hash tables or other mechanisms that, on average, provide access times that are sublinear on the number of elements in the collection. The data structures used in this Map objects specification is only intended to describe the required observable semantics of Map objects. It is not intended to be a viable implementation model." – Oriol May 23 '16 at 04:11
-
@guest271314 Maybe the size was too much. Try http://pagedemos.com/84xj3qxfm7cz/4 – Oriol May 23 '16 at 04:14
-
@Oriol: interesting. timing just the size get reveals a big diff, of course. i was wondering more about the over-all usage perf, and now realize it depends a little bit on usage (# of props, # of length assessments versus # of sets), but more testing revealed that on larger collections, even with reading the `.size` each mod, `Map()` outperforms plain objects. Only on small collections, especially with dot-path assignments or literals instead of array notation, are objects systemically faster to build and census. – dandavis May 23 '16 at 04:26
-
-
@Oriol: oh, and thanks for taking the time to illuminate. i learned something today, and that's much appreciated. it crosses my mind that if one is going to invest in a refactoring to a methodical setter (vs assignments), a custom `.set()` method on a plain object could be used to calc the size (with `in`) on-write instead of on-demand, and without internal validations, that may indeed outperform a Map and Object.keys() if there were many reads to each write. But reasonably, i think you're right and we should just use Maps if we need top speed size measurements. – dandavis May 23 '16 at 04:57