Shallow Equality vs Deep Equality in JavaScript

In JavaScript, comparing two values for equality depends heavily on their underlying data types and structure. Understanding the distinction between shallow equality and deep equality is essential for effective state management, performance optimization, and bug prevention. While shallow equality compares primitive values directly and complex objects by memory reference (or by their first-level properties only), deep equality recursively traverses nested structures to verify that every nested key and value matches across both items.

Understanding Shallow Equality

Shallow equality compares values at the surface level. For primitive data types (such as numbers, strings, and booleans), JavaScript compares them by their actual value using operators like === or Object.is.

However, objects, arrays, and functions in JavaScript are reference types. When using the strict equality operator (===), JavaScript checks whether both operands point to the exact same location in memory, not whether their contents are identical.

// Primitive comparison
const a = 5;
const b = 5;
console.log(a === b); // true

// Reference comparison
const obj1 = { name: "Alice" };
const obj2 = { name: "Alice" };
console.log(obj1 === obj2); // false (different memory references)

const obj3 = obj1;
console.log(obj1 === obj3); // true (same memory reference)

In libraries and frameworks like React, shallow equality often refers to a shallow property check. This means iterating over the immediate keys of two objects and verifying that the value of each key is strictly equal (===) to the corresponding key in the other object. If an object contains nested objects, only their references are compared, not their internal values.

Understanding Deep Equality

Deep equality checks whether two entities have identical contents, regardless of their memory references or how deeply nested their structures are. To determine deep equality, an algorithm must recursively traverse every property, array element, and nested object, comparing each nested leaf node for value equality.

const userA = {
  name: "Alice",
  address: { city: "New York", zip: 10001 }
};

const userB = {
  name: "Alice",
  address: { city: "New York", zip: 10001 }
};

// Shallow check: false (userA.address !== userB.address)
// Deep check: true (all nested keys and values match)

JavaScript does not have a built-in operator for deep equality. Common ways to perform deep equality checks include:

Key Differences

Feature Shallow Equality Deep Equality
Depth of Check Top-level properties only All nested levels recursively
Performance Fast (\(O(1)\) or \(O(k)\) where \(k\) is top-level keys) Slower (\(O(n)\) where \(n\) is total nested elements)
Memory Comparison Compares object references Ignores references, compares nested data
Native Support Built-in (===, Object.is) Requires custom logic or external libraries

When to Use Each