DEV Community

Samantha Ming
Samantha Ming

Posted on • Edited on

How to Get an Object Length

Code Tidbit by SamanthaMing.com

Unlike arrays, it's always been tricky to get the object length. Well no more!
Object.keys return an array of all the object's enumerable property keys. And after that, you can simply call length, and voila! You have the length of the object 🎉



const object = {one: '1️⃣', two: '2️⃣'};

// Using Lodash
_.size(object); // 2

// Using JavaScript
Object.keys(object).length; // 2


Enter fullscreen mode Exit fullscreen mode

Why can't we call length on an Object

You might be wondering why can't we just simply call length directly on our object. Let's see what happens when we do:



const object = {one: '1️⃣', two: '2️⃣'};

object.length; // undefined

object.hasOwnProperty('length'); // false


Enter fullscreen mode Exit fullscreen mode

You can't do it because object doesn't have a length property. Only string and arrays have a length property.



const string = 'hello';
const array = [1,2,3];

string.hasOwnProperty('length'); // true
array.hasOwnProperty('length'); // true


Enter fullscreen mode Exit fullscreen mode

What are Enumerables

Alright, let's cover another topic. I mentioned at the beginning that Object.keys returns an array of enumerable property keys. So let's figure out where this enumerable attribute comes from.

Assigning a Property

Typically, when we want to add a property to an object, we might just use the dot notation:



const object = {};

object.one = '1️⃣';

console.log(object); // { one: '1️⃣' }


Enter fullscreen mode Exit fullscreen mode

Defining a Property

Alternatively, we can also use Object.defineProperty. It accepts 3 parameters. And it's in the property descriptor where we can set our enumerable attribute.



Object.defineProperty(object name, property name, property descriptor)


Enter fullscreen mode Exit fullscreen mode

Alright, let's define a property with this method:



const object = {};

Object.defineProperty(
  object,
  'one', {
    value: '1️⃣'
  }
);

console.log(object); // {} 
// ☝️ Why is it empty? 🤔


Enter fullscreen mode Exit fullscreen mode

Hmmm...that's odd. Why didn't our property show up 🤔 Well, that's because when we define a property this way, the enumerable attribute is by default false. So if we want it to show up, we need to set true to it.



const object = {};

Object.defineProperty(
  object,
  'one', {
    value: '1️⃣',
    enumerable: true // 👈
  }
);

console.log(object); // { one: '1️⃣' } 
// ☝️ Great, it shows up now!


Enter fullscreen mode Exit fullscreen mode

Enumerable defaults to true

Let's go back to our object property example that we set with the dot notation. Why did it show up automatically? Well, that's because when we assign a property that way, the enumerable attribute is automatically set to true.



const object = {};

object.one = '1️⃣';

object.propertyIsEnumerable('one'); // true


Enter fullscreen mode Exit fullscreen mode

Enumerable Summary

For most of us, we would rarely touch the enumerable attribute when defining our property. It's simply a way for us to control if the particular property we created will show up or stay hidden when we iterate over the object using Object.keys.

If you want to learn more about enumerability, I recommend reading this article, Enumerability in ECMAScript 6.

Therefore, the attribute enumerable is used to hide properties that should not be iterated over. That was the reason for introducing enumerability in ECMAScript 1.

Dr. Axel Rauschmayer, 2Ality

Object.keys vs Object.getOwnPropertyNames

Now that you understand enumerable, let's cover another method that you might see as an option to get the length, Object.getOwnPropertyNames.



const object = {one: '1️⃣'};

Object.defineProperty(
  object,
  'two', {
    value: '2️⃣',
    enumerable: false
  }
);

Object.keys(object); // [ 'one' ]

Object.getOwnPropertyNames(object); // [ 'one', 'two' ]


Enter fullscreen mode Exit fullscreen mode

As you can see Object.getOwnPropertyNames will return ALL property keys, whereas Object.keys will just return the enumerable property keys. As I mentioned before, enumerable attributes are maybe hidden for a reason, so you might not want to access that. Therefore, Object.getOwnPropertyName might not be the method you want to use to get the length of an object.

Object Length with Symbols

Before you default to Object.keys to get the object length. I want to point out one more consideration. In ECMAScript 6, ES6, a new primitive data type was introduced called symbol. And you can use symbol as a property name on an object.



const animal = {
  [Symbol('ghost')]: '👻',
  turtle: '🐢'
}; 


Enter fullscreen mode Exit fullscreen mode

But the gotcha is when you have a symbol as a property name. Object.keys nor Object.getOwnPropertyNames will work.



Object.keys(animal);
// [ 'turtle' ] <-- no symbol

Object.getOwnPropertyNames(animal);
// [ 'turtle' ] <-- no symbol


Enter fullscreen mode Exit fullscreen mode

So a solution is to use Object.getOwnPropertySymbols



Object.getOwnPropertySymbols(animal);
// [ Symbol(ghost) ]


Enter fullscreen mode Exit fullscreen mode

Now combining the two methods, you will get the proper length.



const enumerableLength = Object.keys(animal).length;
const symbolLength = Object.getOwnPropertySymbols(animal).length;

const totalObjectLength = enumerableLength + symbolLength;
// 2 <-- 👍

Enter fullscreen mode Exit fullscreen mode




Community Input

@Eugene Karataev: Chrome displays the non-enumerable properties in the console. It just shows them slightly differently - not as bright as the enumerable ones

Thanks Eugene Karataev


Resources


Thanks for reading ❤
Say Hello! Instagram | Twitter | Facebook | Medium | Blog

Top comments (24)

Collapse
 
karataev profile image
Eugene Karataev

Btw, Chrome displays not enumerable properties in the console. It just shows them slightly differently - not as bright as enumerable ones.
not enumerable

Collapse
 
samanthaming profile image
Samantha Ming • Edited

Wooo... that's interesting! good to know, thanks for sharing that! Let me add this my notes 👍

Collapse
 
sebvercammen profile image
Sébastien Vercammen • Edited

Semantics: A JS object is a collection of properties, keys that map to their respective values, with keys that can only be strings or symbols. It doesn't have a length.

Similar to asking "What is the length of your car?" and giving the answer "The length of my car is 14, because it has 4 doors, a trunk, 6 windows, and 4 wheels".

(Simplified example.)

Using Object.keys().length or Object.getOwnPropertyNames().length gives the length of the list of enumerable keys (or all property names for the latter), not of an object.

Not judging though. I just enjoy being explicit/intentional with wording when I can. Good article and thanks for sharing. :)

Something you could add: Using an object as a key calls .toString(), which will make all object keys conflict on the key "[object Object]". ES6' Map works with objects but uses their memory address as keys, so an exact copy of an object will have a different key (no deep comparison, for efficiency).

Collapse
 
samanthaming profile image
Samantha Ming • Edited

Totally fair assessment! I guess I always just associated length to the size, since length is the property being called for array or strings. So naturally when I was thinking of getting the size of an object, I automatically default to referring it to length as well 😅 I guess that's why Lodash opted for size and not length. This is probably the best thing with sharing an article. It always opens up a conversation. I'm glad you shared your comment! Now, I learned something. Thank you for explaining with such clarity! 😊

Collapse
 
sebvercammen profile image
Sébastien Vercammen

You're absolutely right. Semantics, to define the meaning of things, is great to have conversations about if you find the right people.

Meaning is flexible, after all, until something is defined. Exploring this creates new understanding and perspectives, which works wonders to break out of black/white thinking.

Collapse
 
danielescoz profile image
Daniel Escoz

Maybe length is the wrong term, but it's perfectly reasonable to define an object's size the way it's done in this post.

Collapse
 
samanthaming profile image
Samantha Ming

Thanks for chiming in Daniel! Now I can see why Lodash chose size instead of length 😅

Thread Thread
 
danielescoz profile image
Daniel Escoz

Notice also that JavaScript itself is choosing size for types like Set or Map: size is a more generic (and mathematical) name that suits more needs better, but nitpicking and pedantry aside, length is perfectly a understandable (and I keep using it for Sets and Maps until I remember that's wrong).

Thread Thread
 
sebvercammen profile image
Sébastien Vercammen

Clarifying meaning isn't pedantic.

Using size and capacity instead of length on data structures with dynamic lengths was done before JS.

There was probably a discussion somewhere, where they argued for/against both.

Python implements len() as a function with the magic method __len__ precisely to have one consistent way of retrieving an intuitive "length".

Collapse
 
gypsydave5 profile image
David Wickes • Edited

I enjoyed this article! "How to get an Object Length" really undersells it. Didn't know about the enumerable property - or the weird thing with symbols. Great piece of writing.

How would you use these features? I can understand enumerable being useful to get some level of 'privacy'/encapsulation into an JavaScript object. Are symbols with keys the same thing but more so? Are there any other uses?

Collapse
 
samanthaming profile image
Samantha Ming

Thanks David for the kind feedback! In regards to symbols, from the readings I gathered, it seems to serve one main purpose: create property keys without risking name collisions (since symbols are always unqiue). I have not personally used symbols in my daily programming yet. if you know of any other use cases, please do share. Might be an interesting one to cover in a future post, have to dig into it a bit further 😊

Collapse
 
nickymeuleman profile image
Nicky Meuleman • Edited

Great writeup!

The enumerable and Symbols parts were especially excellent.

This made me play around with your example code a bit and I have a question.

const numbers = {one: '1️⃣'};

Object.defineProperty(
  numbers,
  Symbol.for('two'), {
    value: '2️⃣',   
    enumerable: false // default value
  },
);

const enumerableLength = Object.keys(numbers).length; // 1
const symbolLength = Object.getOwnPropertySymbols(numbers).length; // 1
const totalObjectLength = enumerableLength + symbolLength; // 2

Enter fullscreen mode Exit fullscreen mode

How should I handle this case where I don't want the symbol to get counted?

edit:
Came up with this, other solutions?

const enumerableSymbolLength = Object.getOwnPropertySymbols(numbers).filter(key => numbers.propertyIsEnumerable(key)).length // 0
const totalObjectLength = enumerableLength + enumerableSymbolLength; // 1
Enter fullscreen mode Exit fullscreen mode
Collapse
 
samanthaming profile image
Samantha Ming

If you only want the enumerable properties without the symbols. The Object.keys method should just work, since it doesn't include that. If I misunderstood your questions, please follow up 🙂

Collapse
 
nickymeuleman profile image
Nicky Meuleman • Edited

All enumerable properties, including ones with Symbols as keys.
Excluding all non-enumerable properties.

an object with:
1 enumerable property with string as key,
2 non-enumerable properties with a string as key,
1 enumerable property with Symbol as key
1 non-enumerable properties with Symbol as key.

Should return 2 as total length. (1 for string key and 1 for Symbol key)

Collapse
 
karataev profile image
Eugene Karataev

Wait.
At first you said that Object.keys don't return hidden properties.
In the end of the article you use this method to count a number of object's properties. I guess you should use Object.getOwnPropertyNames(animal).length instead of Object.keys(animal).length.

Collapse
 
samanthaming profile image
Samantha Ming

Which part? Hmm...i don't think i see it 😲

Collapse
 
karataev profile image
Eugene Karataev

Here's your code in the end of the article to count total amount of an object's properties.

const enumerableLength = Object.keys(animal).length;
const symbolLength = Object.getOwnPropertySymbols(animal).length;
const totalObjectLength = enumerableLength + symbolLength;
// 2 <-- 👍

Let's take a look at this object:

let animal = {head: 1};
Object.defineProperty(animal, 'legs', {value: 4});

This object has two properties, but your code above will return 1. So my thought was that it's better to replace Object.keys with Object.getOwnPropertyNames to return correct amount of an object's total properties.

Collapse
 
markokolombo profile image
Marko Kolombo

Deeply covered, nice!

As a workaround, what about Object.values().length ?

Collapse
 
krumpet profile image
Ran Lottem

I think Object.values and Object.keys will have the same length, as they both consider only enumerable properties:

Docs for Object.values

Collapse
 
markokolombo profile image
Marko Kolombo • Edited

true story...

const object1 = {
  a: 'somestring',
  b: 42,
  c: false,
  [Symbol('ghost')]: '👻'
};

console.log(Object.values(object1).length); //>3
Thread Thread
 
krumpet profile image
Ran Lottem

I'm getting 3 for the length of both keys and values. The arrays are ["a", "b", "c"] and ["somestring", 42, false], respectively.

Collapse
 
samanthaming profile image
Samantha Ming

Yup, that works too! Now that i think of it, i should have cover those examples too 😅 next time 😜

Collapse
 
krumpet profile image
Ran Lottem • Edited

Great write-up!

I've used getOwnPropertyNames in the past, along with recursive calls on an object's prototype, to get all of the properties that object has and that it inherited.

Collapse
 
samanthaming profile image
Samantha Ming

Yup that's great use case to use getOwnPropertyNames. I think the key is knowing what you want and picking the right tool for it. Thanks for sharing your use case! 👍