Explain Codes LogoExplain Codes Logo

Object comparison in JavaScript

javascript
object-comparison
javascript-basics
deep-equality
Nikita BarsukovbyNikita Barsukov·Oct 5, 2024
TLDR

Check if two JavaScript objects are identical by using a deep comparison function. Recursively compare each property's value as shown in this concise deepEqual function:

function deepEqual(a, b) { if (a === b) return true; // Even Star Wars fans would agree, these two ARE the droids you're looking for! if (typeof a !== 'object' || typeof b !== 'object' || a == null || b == null) return false; // One isn't an object, Houston we have a problem! let keysA = Object.keys(a), keysB = Object.keys(b); if (keysA.length !== keysB.length) return false; // Unequal property count, quick exit for (let key of keysA) if (!keysB.includes(key) || !deepEqual(a[key], b[key])) return false; // Recursion, beautiful isn't it? return true; } // Example usage: console.log(deepEqual({ a: 1, b: { c: 2 } }, { a: 1, b: { c: 2 } })); // true

Highly useful for simple object comparison, though be warned, corner cases like circular references and built-in type comparisons (Date, RegExp) can be tricky to navigate. Turn to utility libraries like Lodash.isEqual() for the more thorny bits.

The many faces of object comparisons

Object comparison, like an onion, has many layers. For accurate comparison, you need to peel these layers and understand these complexities.

Quirks and nuances

Handling NaN: NaN === NaN is false, because NaN is playing hard to get. Fortunately, deepEqual() can see past this charade by invoking Object.is() or a similar approach.

Prototype junction: Objects displaying identical attributes can have different prototype structures. Remember, appearances can deceive. Relying on Object.hasOwnProperty can help you tell apart the real from the impostors.

Self-referential objects: Circular references are the infinity stones of object comparisons. It's imperative to check for them to avoid being trapped in an infinite loop of madness. Sadly, our deepEqual function isn't equipped with a shield for this. Look towards libraries like Lodash for this.

Function and closures: Comparing functions requires special care. They might look same textually, but different closures can alter their behavior. This calls for more specialized comparison methods like serialization.

The mightier deep comparison

Ready for the big leagues? Here's a more sophisticated deep comparison function:

// A more advanced deep comparison function advancedDeepEqual(a, b) { // For the brave hearts willing to tackle every beast in the land of object comparison }

Refer to good old StackOverflow for in-depth code or adopt Lodash.

Object comparison using JavaScript built-ins

When the mt. Everest of object comparison seems daunting, try the hillocks of Object.is() and strict equality (===). Ideal for simple comparisons and known terrains.

The Object.is() and strict equality divide

While strict equality is great for everyday primitive comparisons, Object.is() can handle peculiarities like differentiating between -0 and +0.

console.log(-0 === +0); // true console.log(Object.is(-0, +0)); // false

The JSON.stringify() approach

JSON.stringify is the late-night pizza delivery of object comparison. Quick and easy by converting an object to a JSON string, but be wary of property order and non-enumerable properties.

The art of object comparison

To craft a clear picture, imagine object comparison in JavaScript as a modern art installation:

Comparing Objects: Object A 🖼: {a: 1, b: 2} Object B 🖼: {a: 1, b: 2} Object C 🖼: {a: 1, b: '2'}

The Perfect Match:

🖼 A == 🖼 B // 👍 True love! (Both look the same)

Mismatch:

🖼 A == 🖼 C // 🙅 No match! (Different Types)

Object comparison best practices

Here are a few nuggets of wisdom to make your object comparison journey smoother.

Undefined properties: the Invisible Men

Properties undefined in both objects often don't really matter for comparisons. They're like extra toppings on a pizza. Most times, we just don't care!

Guarding against infinite loops

Objects referencing themselves can land you in an endless loop! A check for circular references is essential to prevent such an unpleasant infinite trip.

Hand-in-hand with type coercion

Implicit type coercion can break or make a comparison. Always use strict comparison (===) to avoid unexpected surprises unwrapping your comparisons.

Liabilities and libraries

For complex comparisons, reach out for well-tested libraries like Lodash. They come with optimized algorithms, handle edge cases with grace, and can save your precious time and sanity.