Object.size()

Hi all,

With the current version of the spec, there is no a direct way to find the number of own enumerable properties of an object.

The common pattern is:

Object.keys(obj).length

Unfortunately the code above creates a temporary array with all of the own enumerable properties, which I think could be avoided if ES provides an API which returns it directly.

Adding anything to Object.prototype is a nonstarter, and it wouldn't work on a null object anyways, so the only alternative here is something like Object.size(obj) - and then, what about non-enumerable keys? What about Symbol keys (enumerable and non-enumerable)? What about inherited keys?

There simply does not exist a universal definition for an object's "size", which is why Object.keys, or Reflect.ownKeys, or Object.getOwnPropertySymbols, or Object.getOwnPropertyNames, or for (var k in obj) { } are all available options to apply your own definition and generate the length.

In many engines Object.keys tends to have an optimised fast-path, making it less expensive than it looks

Here's V8 for example: https://github.com/v8/v8/blob/1c3b8975a4f986e4c0b07b9704ae39704c614eec/src/objects/keys.cc#L445

Of course this wouldn't apply to all objects, but neither would Object.size. If called on a proxy with a custom ownKeys hook, it can't skip that.

Ashley, to make sure I understand, the "fast path" in this V8 link means that Object.keys() would return an array that the runtime has already created and populated? Whereas the "slow path" means the whole "create a new array and populate it and then later garbage-collect it"?

Thanks for bearing with me! Just want to make sure I understand :smile:

Hi @fasiha

That's correct!

V8 source around here: src/keys.cc - v8/v8 - Git at Google

Let's have a debate on length vs size.

It's a shame length is fairly unique to JS.

Pick one:

Object.keys(obj).length
Object.length(obj)
Object.size(obj)

The odd one out is size, however length is a variable and not a function for an array. So perhaps size is the right one as that's what a Map uses.

My brain is conflicted.

And as it's most commonly used for object data tables. It should probably reflect the public members like other data structures.

Length, to me, implies an ordering as well. An array has a length because there's a start and end to the array, and the length is just the distance between those two.

Things like maps, sets, and objects are unordered. It's odd to talk about a length with them, because the data isn't conceptually lined up into a neat row with a beginning and end, it's more like a bunch of stuff in a bag. Sure, sometimes we use the Object.keys() method to force the object keys into an exact order, and after doing that we take the length, but if we're trying to count the number of properties on the object itself, .size() feels more appropriate to me.

2 Likes

I'm totally in favor of Object.size(obj). Would love to stop having to write Object.keys(obj).length every single time I want to count its keys.

I was about to open this same issue before discovering this one. What a pain this is, and most other object types (arrays, sets, maps) have some sort of mechanism for this. Sure, those are iterables where this is not, but a Object.size(obj) shorthand would be very welcome.

1 Like