Code Snippets
/

Deep Structural Equality Check

Deep Structural Equality Check

Comparing two values structurally is a deceptively hard problem: `===` only checks reference, `JSON.stringify` reorders keys and drops undefined, and naive recursion stack-overflows on cycles. This snippet builds up the comparator step by step: a baseline that handles primitives and plain objects, a typed-aware version that respects Date / RegExp / Map / Set, and a cycle-safe production-grade implementation. Use the version that matches your data shape.

JavaScript
Hard
utility
code-template
recursion

401 views

7

function deepEqualBasic(a, b) {
    if (Object.is(a, b)) return true;
    if (a === null || b === null || typeof a !== 'object' || typeof b !== 'object') {
        return false;
    }
    if (Array.isArray(a) !== Array.isArray(b)) return false;
    const keysA = Object.keys(a);
    const keysB = Object.keys(b);
    if (keysA.length !== keysB.length) return false;
    for (const k of keysA) {
        if (!Object.hasOwn(b, k)) return false;
        if (!deepEqualBasic(a[k], b[k])) return false;
    }
    return true;
}

console.log(deepEqualBasic({ a: 1, b: 2 }, { b: 2, a: 1 }));   // true
console.log(deepEqualBasic([1, [2, 3]], [1, [2, 3]]));         // true
console.log(deepEqualBasic(NaN, NaN));                         // true (Object.is)
console.log(deepEqualBasic({ a: 1 }, { a: 1, b: undefined })); // false (key mismatch)

The skeleton is short: try Object.is first (which gives correct NaN === NaN and distinguishes +0 from -0), then bail on non-objects, then compare own enumerable string keys. The keysA.length !== keysB.length check is the cheap way to catch structural mismatches before the expensive recursion runs. Object.is over === is the small upgrade that a surprising number of hand-rolled equality functions miss. Use this baseline when the inputs are guaranteed to be plain JSON-shaped data.

2 more snippets in this entry are available for premium members.

Upgrade to Premium