Skip to content

feat(isEqual): add isEqual function with its tests and documentation - #102

Merged
AmirabbasJ merged 3 commits into
fullstacksjs:mainfrom
xvyashar:feat/object-is-equal
Sep 6, 2026
Merged

feat(isEqual): add isEqual function with its tests and documentation#102
AmirabbasJ merged 3 commits into
fullstacksjs:mainfrom
xvyashar:feat/object-is-equal

Conversation

@xvyashar

@xvyashar xvyashar commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Function Signature

function isEqual(a: unknown, b: unknown): boolean;

Motivation

isEqual performs a deep equality comparison between two values, recursively comparing nested structures instead of relying on reference equality.

It supports common JavaScript value types including primitives, functions, objects, arrays, dates, regular expressions, maps, sets, and circular references:

// Primitive types
console.log(isEqual("abc", "abc")); // true
console.log(isEqual(1, 1)); // true
console.log(isEqual(null, null)); // true

// Deep object comparison
const obj = { a: { b: { c: 1 } } };
const clonedObj = clone(obj);
console.log(isEqual(obj, clonedObj)); // true

// Deep array comparison
const array = [1, 2, [3, [4, 5, [6, 7]]]];
const clonedArray = clone(array);
console.log(isEqual(array, clonedArray)); // true

// Date comparison
const date1 = new Date("2026-01-01");
const date2 = new Date("2026-01-01");
console.log(isEqual(date1, date2)); // true

// RegExp comparison
const regex1 = new RegExp("abc", "g");
const regex2 = new RegExp("abc", "g");
console.log(isEqual(regex1, regex2)); // true

// Map comparison
const map = new Map([
  ["a", 1],
  ["b", { c: [1, 2] }],
]);
const clonedMap = clone(map);
console.log(isEqual(map, clonedMap)); // true

// Set comparison
const set = new Set([1, 2, "a"]);
const clonedSet = clone(set);
console.log(isEqual(set, clonedSet)); // true

Benefits:

  • Provides reliable deep equality comparison for complex JavaScript values.
  • Handles nested and circular data structures.
  • Supports built-in collections such as Map and Set.

Comment thread src/object/isEqual.ts
Comment on lines +133 to +134
if (isComparedBefore(a as object, b as object, comparedObjects))
return true;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't get this part.
Why do we return true if they have already been compared?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As we can see in the next line, this function immediately adds the current comparison to the map. So, when it reaches the same comparison twice or more, it means:

  • The result of this comparison was true (because this function would have already exited early if the result was false).
  • Or the comparison is still in progress at the parent scope. By returning true, we skip this comparison and let the parent comparison determine the result, while avoiding a circular reference overflowing our call stack.

By the way, I agree that the naming of these functions and "comparedObjects" is kinda misleading. I can think of new names if you want!

@AmirabbasJ
AmirabbasJ self-requested a review September 5, 2026 10:49
Comment thread src/object/isEqual.ts
Comment thread src/object/isEqual.ts
@AmirabbasJ
AmirabbasJ merged commit 988e8fa into fullstacksjs:main Sep 6, 2026
2 checks passed
@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown

馃帀 This PR is included in version 4.24.0 馃帀

The release is available on:

Your semantic-release bot 馃摝馃殌

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants