Understanding JavaScript Objects

Objects are a core concept in JavaScript. When I started learning about Objects it seemed to me pretty straightforward, just pairs of keys and values they said.

It took me some time to realize that this topic is much more complicated than I had in mind. I then started learning from different sources, some were good, but I could never get “the big picture”.

In this post I have tried to create a comprehensive overview of objects in JS, not going too deep into any subject, but just deep enough to help you understand and feel comfortable to go and read further.

So, let’s start from the beginning.

Object

A JavaScript object is just a collection of properties, each property is a pair of a key and a value. 
You can access keys using dot notation( obj.a ) or brackets notation ( obj['a']). Remember that you should use the brackets notation if your key is one of the following:
1. Not a valid JavaScript identifier (has space, dash, starts with a number...) 
2. Is a variable

Objects in JS are created with a property called Prototype which is a very important subject to master.

prototype:

Every object in JavaScript has an internal property called Prototype, in most browsers you can access it as _proto_. Prototype is Javascript’s solution for inheritance, which allows sharing functionality without duplicating the code in memory. It does so by linking one object to another. 
Simply put, Prototype creates a reference from one object to another.

Prototype chain — Every time you look for a property in an object, JS will try to find it on the object, if it can’t, it will look inside the Prototype object. If the property is still missing, JS will go on looking in the Prototype of the linked object. This will continue until JS finds the relevant property or until the end of the prototype chain.

Let’s take an example:

cons is a constructor (just a function that can use the new operator). At line 5 we create new object, a new instance of cons. when created, obj also gets a prototype property.
Now we add properties (‘b’, ‘c’) to the prototype object of cons and let’s take a look at obj :

obj.a // 1 — nothing new here, obj.a is still 1.
obj.c — there is no c property on obj! but just as we said earlier, JS will now look in obj Prototype and will come back with a 4.
 
Now ask yourself what is the value of obj.b and what would be the value after we delete obj.b ?

obj.b is 2 . We did set a b property but on cons Prototype so when we check for obj.b we still get 2. However, after we delete obj.b, JS can’t find b on obj anymore so it goes to its prototype and come back with a 3.

I want to briefly show the different ways to create an object and talk some more about prototype.

creating an object

Object literal: var obj = {a: 1}; we have created an object with the following ptototype chain: obj ---> Object.prototype ---> null 
As you can guess object.prototype is the prototype of object and it is also the end of the prototype chain.

Object.create(): var newObj = Object.create(obj); newObj will have this ptototype chain: newObj ---> obj ---> Object.prototype ---> null

Constructor: As the example above, a constructor is just a JS function that allows us to use new operator to create instances of it.

ES6 Classes:

class rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
  getArea() {
return this.height * this.width;
}
}
let square = new rectangle(2, 2);

Square is an instance of rectangle constructor, so we can call square.getArea() //4, square.width and also all the functions it inherited from object.prototype.

Which way should you choose? If you plan to create several instances you better use ES6 / constructor method but if you plan to create a one time object you might want to choose object literal because it is probably the easiest.

Now that we know about prototype and are familiar with all the ways to create new objects we can move forward talking about one of the most confusing parts in objects:

Comparing & changing Objects

In JavaScript objects are a reference type. 
When we create an object var obj = {a: 1}; the variable obj receives the location in memory of the object and not the value! This is extremely important to understand because it can cause a variety of errors. When we create another object var newObj = obj , we have actually created a pointer to the location in memory of the obj and not a totally new object. 
This means that when we do newObj.a = 2 we actually change obj so obj.a is now 2 ! 
This is so bug prone that many companies are working with immutable objects, meaning you can not change the object you have created. Instead you have to create a new object (a copy of the original one) and change it. This is the way important libraries like Redux are working and it is one of the most important concepts in functional programming. You can read more about it here.

Equality: This also means that two objects are never equal, even if they have the exact same properties. This is because JS actually compares the location in memory of the objects and two objects can never be in the same memory cell.

// Two distinct objects with the same properties are not equal
var fruit = {name: 'apple'};
var fruitbear = {name: 'apple'};
fruit === fruitbear; // return false
// here fruit and fruitbear are pointing to same object
var fruit = {name: 'apple'};
var fruitbear = fruit;
fruit === fruitbear; // return true

So by now you might be thinking how can I compare objects or how should I manipulate objects immutably?

Let’s go over some possibilities:

Object changing:

We understand we better not mutate our objects, so we would like to create a copy of the relevant object and change its properties. 
object.assign() to the rescue.

var obj = { a : 1, b : 2};
var newObj = Object.assign({}, obj,{a:2}) // {a : 2, b : 2 }

If we want to change a property value of obj we can use object.assign to create a copy of obj and change it.
You can see how we first create an empty object, then copy the values of obj and later add our changes so eventually we get a new updated object to use.

Please pay attention that this will not work for a deep copy . A deep copy is when we want to copy an object which has one object property or more:

const obj = {a : 1, b : { a : 1 } };  // b property is an object

Object.assign()copies property values, so when the property value is a reference to an object, it only copies that reference.

For deep copy we have to copy recursively. We could create a function or simply use _.cloneDeep of Lodash.

Object comparing :

One cool trick for working with objects is to stringify them. 
What we do here is to stringify both objects, and then compare the resulted strings :

JSON.stringify(obj1) === JSON.stringify(obj2) 

This works because we now compare strings which is a reference done by value data type. The bad news is that it is not always going to work, mainly because object properties order is not guaranteed.

Another good solution is to use Lodash’s _.isEqual which is making a deep object comparison.

Before we finish, lets go over some object’s interview questions which will help us dive in some more and to practice what we have learned.
 
Try to think about an answer before going on reading the rest.

How to find out the length of an object?

To find the answer we would need to iterate over the object properties one by one and to count them. There are number of ways to iterate over an object:

  • for in: This method traverses all enumerable properties of an object and its prototype chain. Now that we (hopefully) know prototype we can easily realize that if we want to get only the object properties it might not be right to use for in.
  • object.keys: This method returns an array with all the own (only on object) enumerable properties keys of an object. This is better because we are only working on the object properties without its prototype properties. Rarely you will set property’s enumerable attribute to false, causing object.keys to skip them and you might not get the result you were wishing for. This is where getOwnPropertyNames can be handy.
  • getOwnPropertyNames returns an array containing all object own keys (enumerable or not).

Also worth mentioning:

  • object.values iterate over own and enumerable properties and returns an array with the relevant values.
  • object.entries iterate over own and enumerable properties and returns an array with pairs of keys and values

As you can see, most of the above methods return an array, so you can leverage all of the methods available to JavaScript arrays.
One of this methods is array.length so we can simply write:

let objLength = Object.getOwnPropertyNames(obj).length;

How to check if an object is empty ?

  1. JSON.stringify(myObj) === “{}” — we are using the stringify tool again, which allows us to easily check if the object is empty (comparing strings not objects)
  2. !Object.keys(myobj).length // true — As we said before, converting object’s keys to array can benefit us. Here we are taking advantage of the length property inherited from Array.prototype to check for the length of the keys array. In JS 0 is converted to false so when we add not ! we turn it to true while all other number will result in false.

In Conclusion

We have been through a lot. I hope you now feel somewhat more comfortable creating and dealing with objects.

  • Remember that objects are a reference type, which means you are advised to work immutably.
  • Make friends with the prototype property and the prototype chain.
  • Get familiar with the different tools that help us work with objects. Remember that you can stringify it, create an array of its keys, or just traverse through its properties with one of the various methods we have learned.

I wish you great luck exploring JavaScript objects. Have fun with it!


Feel free to connect with us: Halolabs.io | Twitter | LinkedIn

Liked what you read? Hold down the 👏 to say “thanks!” and help others find this article.

Like what you read? Give Ben Rozenberg a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.