This post compares Node’s deepEqual with a
JSON.stringify based comparison in terms of performance and behavior.
Warning: JSON.stringify may return different strings for two deep equal objects
If the two objects are created in different ways the order of the keys will be different:
Reference equality, shallow equality and deep equality
First of all, let’s look at why we need a deep comparison instead of just using
This is the object we are going to compare against.
user2 ultimately refer to the same object all our comparisons return true.
However, there are many cases where two objects have the same content but don’t reference the same object.
Here the objects have the same data but are not referentially equal.
Finally, let’s not directly re-use any references from
user1 and just re-type the same object literal.
shallowEqual works by comparing each object property of the two users using
===. That means that when it reaches the
address object, it doesn’t go deeper to compare the contents and relies on the two objects having the same reference.
As a result
shallowEqual thinks the two objects are equal in the second example but not in the third.
deepEqual on the other hand goes deeper into the object when it reaches the address. It compares the strings for
=== and decides that the two objects are equal.
Checking for equality with JSON.stringify
Another way to compare two objects is to convert them to JSON and check if the resulting strings are equal:
deepEqual this method cares about the contents of the object, rather than referential equality.
Comparing the performance of JSON.stringify and deepEqual
This was the result:
What a surprise! The reason I was using
deepEqual was that I thought
jsonEqual would be an order of magnitude slower. Turns out it’s actually faster!
Caveats to the performance comparison
However, on the whole it’s still much better to use
deepEqual. (It’s only 42% slower anyway.)
There are two cases where
deepEqual is faster than a JSON comparison.
if the two objects are referentially equal
jsonEqualwill still generate the two complete JSON strings.
deepEqualon the other hand will immediately see that the two options are the same and finish 8000 times more quickly.
jsonEqualis faster at confirming that two objects are equal,
deepEqualis much faster at finding out that they aren’t. As soon as it finds two properties that don’t match up it returns
false, rather than continuing to look for differences.
Differences in behavior between the two methods
A big problem with
jsonEqual is that it can report false negatives. For example it would say that these two objects aren’t equal:
Deep equal is much more robust and doesn’t rely on the ordering of the properties.
Another difference between the two methods is that
JSON.stringify does not serialize functions.
deepEqual will instead check for reference equality between a function and its counterpart in the other object.