It’s easy to compare objects for equality, but not so easy to tell if they contain the same keys and values. But Why? My goal is to explain why determining if two objects contain the same values can be difficult.
Why explain a problem. Just give me the solution?
Because understanding what is difficult or does not work, can give us a deeper understanding of why and often lead us to look for, or develop solutions, that will work. A link to a great video is at the end of this story.
Primitive data types versus Reference (non-primitive) types
As I will demonstrate, through code and analogy, variables containing a primitive type are given a **value **in memory. Variables containing a non-primitive type are given a **reference **in memory.
Primitive type and memory allocation
The primitive types, keeping it simple, are number, string, boolean, undefined and null. A full list can be found here.
Primitives have a value in memory
What’s happening? For any primitive, memory is allocated and the value of the primitive is stored in that memory location.
To borrow a common analogy, lets say I write the number 1 on a sticky note and put it on the white board. It is to remind myself that I have one task today. (Of course I could write the task but let’s keep it simple.)
My office partner writes the number 1 on a sticky note to remind himself what time he has a meeting and puts it on the white board as well.
The sticky notes are different and each contain their own value.
Think of each sticky note as memory allocated and the number as the value stored in the allocated memory. When compared, in this case, they contain the same value, 1.
When we compare primitives, we compare the values stored in the memory locations.
If I get a new task and change my sticky note to 2, then it does not affect the other sticky note. They each have their own value.
Each has their own memory allocation
The variable, a, was allocated memory and given the value of 1. Variable b was given it’s own memory space and given the value of the variable a, 1. It does not point to a, it is independent of a, and contains it’s own value.
So when the variable a is changed, the variable b remains the same.
Reference type and memory allocation
Reference types, to keep it simple, are Objects, Functions and Arrays, collectively known as objects. More information can be found here.
The variables obj1 and obj2 contain a reference. Each to a separate memory location.
The important thing to understand here is that the variables, obj1 and obj2 (which could be an Object, Array or Function) each contain only a reference to a location in memory. Not the value of the object.
The locations are separate, so the references are different, and the comparison fails. We are not comparing the values of the objects, but the references to their memory locations.
Back to our sticky note analogy.
If I decide to create a list of tasks (not primitive) and place it on my desk, the sticky note on the white board contains information telling me where to look for the list, not the list itself.
The sticky note contains a message like “look on the desk, bottom left corner.”
If I decide to create a second task list, and put that on my desk, another sticky is placed on the white board telling me where to look for the second list, “look on the desk, bottom right corner.)
If I compare the sticky note messages on the white board, they are not equal.
So even if task list 2 is the same as task list 1 (same or different order) the references are different and they will not be equal.
Assigning Reference Types
If you recall in Example 2, we assigned a primitive to the variable a. We then assigned to the variable b the value in the variable a.
Because each had their it’s memory space, changing the value of the variable, a, did not change the value of the variable, b.
With reference types it is different.
Both variables contain the same information, a reference to the object’s location.
In this case they are equal, because the variables contain the same information, the same reference to the object’s location in memory.
In the sticky note analogy, it is as if I had two sticky notes on the white board telling me where to find the original list (on the desk, bottom left corner.) They contain the same information, so are equal.
Changing the value of either obj1 or obj2 changes the other since they both point to the same object. (Compare to Example 2.)
They both have the same reference to the same object.
How do we compare objects?
Comparing objects is easy, use === or Object.is(). This function returns true if they have the same reference and false if they do not.
Again, let me stress, it is comparing the references to the objects, not the keys and values of the objects.
So, from Example 3, Object.is(obj1,obj2); would return false. In Example 4, Object.is(obj1,obj2); would return true.
So even if two objects contain the same data, === and Object.is() will return false, unless the variables contain a reference to the same object.
Comparing object keys and values is more complex.
Possibly Simple Solution
One possible simple solution is to JSON.stringify the objects and then compare the strings. This works fine if the keys are in the same order. This cannot be guaranteed however. In addition, you are comparing strings, not objects.
So we have seen that comparing two objects is more than just looking at the variables. These variables only contain references.
Determining if they contain the same values can be a complex process.
I highly recommend this youtube video on programmatically determining if two object values equal each other.
as well as look in to the following npm package. Lodash’s, _.isEqual().
Thanks for reading and happy coding!