diff options
Diffstat (limited to 'lib/internal/util/comparisons.js')
-rw-r--r-- | lib/internal/util/comparisons.js | 153 |
1 files changed, 47 insertions, 106 deletions
diff --git a/lib/internal/util/comparisons.js b/lib/internal/util/comparisons.js index d072608906..3470f20666 100644 --- a/lib/internal/util/comparisons.js +++ b/lib/internal/util/comparisons.js @@ -14,7 +14,9 @@ const { isStringObject, isBooleanObject, isBigIntObject, - isSymbolObject + isSymbolObject, + isFloat32Array, + isFloat64Array } = require('internal/util/types'); const { getOwnNonIndexProperties, @@ -84,18 +86,6 @@ function areEqualArrayBuffers(buf1, buf2) { compare(new Uint8Array(buf1), new Uint8Array(buf2)) === 0; } -function isFloatTypedArrayTag(tag) { - return tag === '[object Float32Array]' || tag === '[object Float64Array]'; -} - -function isArguments(tag) { - return tag === '[object Arguments]'; -} - -function isObjectOrArrayTag(tag) { - return tag === '[object Array]' || tag === '[object Object]'; -} - function isEqualBoxedPrimitive(val1, val2) { if (isNumberObject(val1)) { return isNumberObject(val2) && @@ -132,13 +122,38 @@ function isEqualBoxedPrimitive(val1, val2) { // For strict comparison, objects should have // a) The same built-in type tags // b) The same prototypes. -function strictDeepEqual(val1, val2, memos) { - if (typeof val1 !== 'object') { - return typeof val1 === 'number' && numberIsNaN(val1) && - numberIsNaN(val2); + +function innerDeepEqual(val1, val2, strict, memos) { + // All identical values are equivalent, as determined by ===. + if (val1 === val2) { + if (val1 !== 0) + return true; + return strict ? objectIs(val1, val2) : true; } - if (typeof val2 !== 'object' || val1 === null || val2 === null) { - return false; + + // Check more closely if val1 and val2 are equal. + if (strict) { + if (typeof val1 !== 'object') { + return typeof val1 === 'number' && numberIsNaN(val1) && + numberIsNaN(val2); + } + if (typeof val2 !== 'object' || val1 === null || val2 === null) { + return false; + } + if (getPrototypeOf(val1) !== getPrototypeOf(val2)) { + return false; + } + } else { + if (val1 === null || typeof val1 !== 'object') { + if (val2 === null || typeof val2 !== 'object') { + // eslint-disable-next-line eqeqeq + return val1 == val2; + } + return false; + } + if (val2 === null || typeof val2 !== 'object') { + return false; + } } const val1Tag = objectToString(val1); const val2Tag = objectToString(val2); @@ -146,9 +161,6 @@ function strictDeepEqual(val1, val2, memos) { if (val1Tag !== val2Tag) { return false; } - if (getPrototypeOf(val1) !== getPrototypeOf(val2)) { - return false; - } if (Array.isArray(val1)) { // Check for sparse arrays and general fast path if (val1.length !== val2.length) { @@ -159,10 +171,10 @@ function strictDeepEqual(val1, val2, memos) { if (keys1.length !== keys2.length) { return false; } - return keyCheck(val1, val2, kStrict, memos, kIsArray, keys1); + return keyCheck(val1, val2, strict, memos, kIsArray, keys1); } if (val1Tag === '[object Object]') { - return keyCheck(val1, val2, kStrict, memos, kNoIterator); + return keyCheck(val1, val2, strict, memos, kNoIterator); } if (isDate(val1)) { if (dateGetTime(val1) !== dateGetTime(val2)) { @@ -174,13 +186,16 @@ function strictDeepEqual(val1, val2, memos) { } } else if (isNativeError(val1) || val1 instanceof Error) { // Do not compare the stack as it might differ even though the error itself - // is otherwise identical. The non-enumerable name should be identical as - // the prototype is also identical. Otherwise this is caught later on. - if (val1.message !== val2.message) { + // is otherwise identical. + if (val1.message !== val2.message || val1.name !== val2.name) { return false; } } else if (isArrayBufferView(val1)) { - if (!areSimilarTypedArrays(val1, val2)) { + if (!strict && (isFloat32Array(val1) || isFloat64Array(val1))) { + if (!areSimilarFloatArrays(val1, val2)) { + return false; + } + } else if (!areSimilarTypedArrays(val1, val2)) { return false; } // Buffer.compare returns true, so val1.length === val2.length. If they both @@ -191,17 +206,17 @@ function strictDeepEqual(val1, val2, memos) { if (keys1.length !== keys2.length) { return false; } - return keyCheck(val1, val2, kStrict, memos, kNoIterator, keys1); + return keyCheck(val1, val2, strict, memos, kNoIterator, keys1); } else if (isSet(val1)) { if (!isSet(val2) || val1.size !== val2.size) { return false; } - return keyCheck(val1, val2, kStrict, memos, kIsSet); + return keyCheck(val1, val2, strict, memos, kIsSet); } else if (isMap(val1)) { if (!isMap(val2) || val1.size !== val2.size) { return false; } - return keyCheck(val1, val2, kStrict, memos, kIsMap); + return keyCheck(val1, val2, strict, memos, kIsMap); } else if (isAnyArrayBuffer(val1)) { if (!areEqualArrayBuffers(val1, val2)) { return false; @@ -209,66 +224,7 @@ function strictDeepEqual(val1, val2, memos) { } else if (isBoxedPrimitive(val1) && !isEqualBoxedPrimitive(val1, val2)) { return false; } - return keyCheck(val1, val2, kStrict, memos, kNoIterator); -} - -function looseDeepEqual(val1, val2, memos) { - if (val1 === null || typeof val1 !== 'object') { - if (val2 === null || typeof val2 !== 'object') { - // eslint-disable-next-line eqeqeq - return val1 == val2; - } - return false; - } - if (val2 === null || typeof val2 !== 'object') { - return false; - } - const val1Tag = objectToString(val1); - const val2Tag = objectToString(val2); - if (val1Tag === val2Tag) { - if (isObjectOrArrayTag(val1Tag)) { - return keyCheck(val1, val2, kLoose, memos, kNoIterator); - } - if (isArrayBufferView(val1)) { - if (isFloatTypedArrayTag(val1Tag)) { - return areSimilarFloatArrays(val1, val2); - } - return areSimilarTypedArrays(val1, val2); - } - if (isDate(val1) && isDate(val2)) { - return val1.getTime() === val2.getTime(); - } - if (isRegExp(val1) && isRegExp(val2)) { - return areSimilarRegExps(val1, val2); - } - if (val1 instanceof Error && val2 instanceof Error) { - if (val1.message !== val2.message || val1.name !== val2.name) - return false; - } - // Ensure reflexivity of deepEqual with `arguments` objects. - // See https://github.com/nodejs/node-v0.x-archive/pull/7178 - } else if (isArguments(val1Tag) || isArguments(val2Tag)) { - return false; - } - if (isSet(val1)) { - if (!isSet(val2) || val1.size !== val2.size) { - return false; - } - return keyCheck(val1, val2, kLoose, memos, kIsSet); - } else if (isMap(val1)) { - if (!isMap(val2) || val1.size !== val2.size) { - return false; - } - return keyCheck(val1, val2, kLoose, memos, kIsMap); - } else if (isSet(val2) || isMap(val2)) { - return false; - } - if (isAnyArrayBuffer(val1) && isAnyArrayBuffer(val2)) { - if (!areEqualArrayBuffers(val1, val2)) { - return false; - } - } - return keyCheck(val1, val2, kLoose, memos, kNoIterator); + return keyCheck(val1, val2, strict, memos, kNoIterator); } function getEnumerables(val, keys) { @@ -370,21 +326,6 @@ function keyCheck(val1, val2, strict, memos, iterationType, aKeys) { return areEq; } -function innerDeepEqual(val1, val2, strict, memos) { - // All identical values are equivalent, as determined by ===. - if (val1 === val2) { - if (val1 !== 0) - return true; - return strict ? objectIs(val1, val2) : true; - } - - // Check more closely if val1 and val2 are equal. - if (strict === true) - return strictDeepEqual(val1, val2, memos); - - return looseDeepEqual(val1, val2, memos); -} - function setHasEqualElement(set, val1, strict, memo) { // Go looking. for (const val2 of set) { |