- ✅ Handles circular references correctly
- ✅ Supports all modern JS data types
- ✅ Correctly handles special cases like NaN comparisons
- ✅ Lightweight with zero dependencies
- ✅ Fast, while handling all cases
When comparing objects in JavaScript, the built-in equality operators (==
and ===
) only check for reference
equality, not structural equality. This means that two objects with the same properties and values will be considered
different if they're not the same instance.
Many deep equality solutions exist (like lodash's isEqual
, fast-deep-equal, and others), but they often have
limitations:
- Some don't handle circular references
- Some have inconsistent behavior with special values like NaN
- Some don't support newer JavaScript features or types
This package aims to provide a comprehensive single solution that addresses all these concerns while maintaining excellent performance.
# Using npm
npm install @ver0/deep-equal
# Using yarn
yarn add @ver0/deep-equal
# Using pnpm
pnpm add @ver0/deep-equal
The API is extremely simple - just import the isEqual
function and use it to compare any two values:
import {isEqual} from '@ver0/deep-equal';
// Comparing objects
isEqual({a: 1, b: 2}, {a: 1, b: 2}); // true
isEqual({a: 1, b: 2}, {a: 1, b: 3}); // false
// Handling circular references
const obj1 = {a: 1};
const obj2 = {a: 1};
obj1.self = obj1;
obj2.self = obj2;
isEqual(obj1, obj2); // true
// Works with various data types and containers
isEqual(new Date('2023-01-01'), new Date('2023-01-01')); // true
isEqual(new Set([1, 2]), new Set([1, 2])); // true
isEqual(new Map([['a', 1]]), new Map([['a', 1]])); // true
isEqual(/abc/g, /abc/g); // true
// Correctly handles special cases
isEqual(NaN, NaN); // true
Check out the benchmarks by running npm run benchmark
in the project directory.
While benchmark results may show this package isn't the fastest solution available, this is a deliberate trade-off.
The performance cost comes from supporting circular reference detection. Rather than splitting this into separate functions, I've prioritized simplicity in both the API design and implementation, eliminating the need for users to choose between different comparison functions.
- Primitive values (numbers, strings, booleans, undefined, null)
- NaN (correctly compared to be equal to itself)
- Plain objects
- Arrays
- Sets
- Maps
- Regular Expressions
- Date objects
- ArrayBuffers
- TypedArrays (Int8Array, Uint8Array, etc.)
- Objects with null prototypes
- Any objects with circular references