From 58b6d0528a4654f28d4a928a9cce3c3d5c0c9271 Mon Sep 17 00:00:00 2001 From: Patrick McCann Date: Fri, 31 Jan 2025 10:12:56 -0500 Subject: [PATCH 1/3] Core: mild speedup on deepEqual a bit faster for arrays, also avoids repeated calls to Object.keys --- src/utils.js | 56 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/src/utils.js b/src/utils.js index 015b1142d47..3df6f5f2426 100644 --- a/src/utils.js +++ b/src/utils.js @@ -998,30 +998,58 @@ export function buildUrl(obj) { * @param {boolean} [options.checkTypes=false] - If set, two objects with identical properties but different constructors will *not* be considered equivalent. * @returns {boolean} - Returns `true` if the objects are equivalent, `false` otherwise. */ -export function deepEqual(obj1, obj2, {checkTypes = false} = {}) { +export function deepEqual(obj1, obj2, { checkTypes = false } = {}) { + // Quick reference check if (obj1 === obj2) return true; - else if ( - (typeof obj1 === 'object' && obj1 !== null) && - (typeof obj2 === 'object' && obj2 !== null) && - (!checkTypes || (obj1.constructor === obj2.constructor)) + + // If either is null or not an object, do a direct equality check + if ( + typeof obj1 !== 'object' || obj1 === null || + typeof obj2 !== 'object' || obj2 === null ) { - const props1 = Object.keys(obj1); - if (props1.length !== Object.keys(obj2).length) return false; - for (let prop of props1) { - if (obj2.hasOwnProperty(prop)) { - if (!deepEqual(obj1[prop], obj2[prop], {checkTypes})) { - return false; - } - } else { + return false; + } + + // Special case: both are arrays + if (Array.isArray(obj1) && Array.isArray(obj2)) { + if (obj1.length !== obj2.length) return false; + for (let i = 0; i < obj1.length; i++) { + if (!deepEqual(obj1[i], obj2[i], { checkTypes })) { return false; } } return true; - } else { + } + // If only one is an array, they’re not equal + else if (Array.isArray(obj1) || Array.isArray(obj2)) { + return false; + } + + // If we’re checking types, compare constructors (e.g., plain object vs. Date) + if (checkTypes && obj1.constructor !== obj2.constructor) { return false; } + + // Compare object keys. Cache keys for both to avoid repeated calls. + const keys1 = Object.keys(obj1); + const keys2 = Object.keys(obj2); + + if (keys1.length !== keys2.length) return false; + + for (const key of keys1) { + // If `obj2` doesn't have this key or sub-values aren't equal, bail out. + if (!Object.prototype.hasOwnProperty.call(obj2, key)) { + return false; + } + if (!deepEqual(obj1[key], obj2[key], { checkTypes })) { + return false; + } + } + + return true; } + export function mergeDeep(target, ...sources) { if (!sources.length) return target; const source = sources.shift(); From e5c37a7babbcecd2f2d85bb344e9fb697a4e06dc Mon Sep 17 00:00:00 2001 From: Patrick McCann Date: Fri, 31 Jan 2025 10:18:56 -0500 Subject: [PATCH 2/3] Update utils.js --- src/utils.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/utils.js b/src/utils.js index 3df6f5f2426..7d2d8fe7336 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1019,9 +1019,7 @@ export function deepEqual(obj1, obj2, { checkTypes = false } = {}) { } } return true; - } - // If only one is an array, they’re not equal - else if (Array.isArray(obj1) || Array.isArray(obj2)) { + } else if (Array.isArray(obj1) || Array.isArray(obj2)) { return false; } @@ -1049,7 +1047,6 @@ export function deepEqual(obj1, obj2, { checkTypes = false } = {}) { return true; } - export function mergeDeep(target, ...sources) { if (!sources.length) return target; const source = sources.shift(); @@ -1273,7 +1270,7 @@ export function hasNonSerializableProperty(obj, checkedObjects = new Set()) { * * @param {Array} collection - Array of objects. * @param {String} key - Key of nested property. - * @returns {any, undefined} - Value of nested property. + * @returns {any|undefined} - Value of nested property. */ export function setOnAny(collection, key) { for (let i = 0, result; i < collection.length; i++) { From 1d763f1d213cd050844dbf8e35879c172ec5dc7a Mon Sep 17 00:00:00 2001 From: Patrick McCann Date: Fri, 31 Jan 2025 10:27:24 -0500 Subject: [PATCH 3/3] Update utils.js --- src/utils.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/utils.js b/src/utils.js index 7d2d8fe7336..5992e5bbdd9 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1009,9 +1009,11 @@ export function deepEqual(obj1, obj2, { checkTypes = false } = {}) { ) { return false; } - + // Cache the Array checks + const isArr1 = Array.isArray(obj1); + const isArr2 = Array.isArray(obj2); // Special case: both are arrays - if (Array.isArray(obj1) && Array.isArray(obj2)) { + if (isArr1 && isArr2) { if (obj1.length !== obj2.length) return false; for (let i = 0; i < obj1.length; i++) { if (!deepEqual(obj1[i], obj2[i], { checkTypes })) { @@ -1019,7 +1021,7 @@ export function deepEqual(obj1, obj2, { checkTypes = false } = {}) { } } return true; - } else if (Array.isArray(obj1) || Array.isArray(obj2)) { + } else if (isArr1 || isArr2) { return false; }