103 lines
3.3 KiB
JavaScript
103 lines
3.3 KiB
JavaScript
|
var equalArrays = require('./equalArrays'),
|
||
|
equalByTag = require('./equalByTag'),
|
||
|
equalObjects = require('./equalObjects'),
|
||
|
isArray = require('../lang/isArray'),
|
||
|
isTypedArray = require('../lang/isTypedArray');
|
||
|
|
||
|
/** `Object#toString` result references. */
|
||
|
var argsTag = '[object Arguments]',
|
||
|
arrayTag = '[object Array]',
|
||
|
objectTag = '[object Object]';
|
||
|
|
||
|
/** Used for native method references. */
|
||
|
var objectProto = Object.prototype;
|
||
|
|
||
|
/** Used to check objects for own properties. */
|
||
|
var hasOwnProperty = objectProto.hasOwnProperty;
|
||
|
|
||
|
/**
|
||
|
* Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
|
||
|
* of values.
|
||
|
*/
|
||
|
var objToString = objectProto.toString;
|
||
|
|
||
|
/**
|
||
|
* A specialized version of `baseIsEqual` for arrays and objects which performs
|
||
|
* deep comparisons and tracks traversed objects enabling objects with circular
|
||
|
* references to be compared.
|
||
|
*
|
||
|
* @private
|
||
|
* @param {Object} object The object to compare.
|
||
|
* @param {Object} other The other object to compare.
|
||
|
* @param {Function} equalFunc The function to determine equivalents of values.
|
||
|
* @param {Function} [customizer] The function to customize comparing objects.
|
||
|
* @param {boolean} [isLoose] Specify performing partial comparisons.
|
||
|
* @param {Array} [stackA=[]] Tracks traversed `value` objects.
|
||
|
* @param {Array} [stackB=[]] Tracks traversed `other` objects.
|
||
|
* @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
|
||
|
*/
|
||
|
function baseIsEqualDeep(object, other, equalFunc, customizer, isLoose, stackA, stackB) {
|
||
|
var objIsArr = isArray(object),
|
||
|
othIsArr = isArray(other),
|
||
|
objTag = arrayTag,
|
||
|
othTag = arrayTag;
|
||
|
|
||
|
if (!objIsArr) {
|
||
|
objTag = objToString.call(object);
|
||
|
if (objTag == argsTag) {
|
||
|
objTag = objectTag;
|
||
|
} else if (objTag != objectTag) {
|
||
|
objIsArr = isTypedArray(object);
|
||
|
}
|
||
|
}
|
||
|
if (!othIsArr) {
|
||
|
othTag = objToString.call(other);
|
||
|
if (othTag == argsTag) {
|
||
|
othTag = objectTag;
|
||
|
} else if (othTag != objectTag) {
|
||
|
othIsArr = isTypedArray(other);
|
||
|
}
|
||
|
}
|
||
|
var objIsObj = objTag == objectTag,
|
||
|
othIsObj = othTag == objectTag,
|
||
|
isSameTag = objTag == othTag;
|
||
|
|
||
|
if (isSameTag && !(objIsArr || objIsObj)) {
|
||
|
return equalByTag(object, other, objTag);
|
||
|
}
|
||
|
if (!isLoose) {
|
||
|
var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),
|
||
|
othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');
|
||
|
|
||
|
if (objIsWrapped || othIsWrapped) {
|
||
|
return equalFunc(objIsWrapped ? object.value() : object, othIsWrapped ? other.value() : other, customizer, isLoose, stackA, stackB);
|
||
|
}
|
||
|
}
|
||
|
if (!isSameTag) {
|
||
|
return false;
|
||
|
}
|
||
|
// Assume cyclic values are equal.
|
||
|
// For more information on detecting circular references see https://es5.github.io/#JO.
|
||
|
stackA || (stackA = []);
|
||
|
stackB || (stackB = []);
|
||
|
|
||
|
var length = stackA.length;
|
||
|
while (length--) {
|
||
|
if (stackA[length] == object) {
|
||
|
return stackB[length] == other;
|
||
|
}
|
||
|
}
|
||
|
// Add `object` and `other` to the stack of traversed objects.
|
||
|
stackA.push(object);
|
||
|
stackB.push(other);
|
||
|
|
||
|
var result = (objIsArr ? equalArrays : equalObjects)(object, other, equalFunc, customizer, isLoose, stackA, stackB);
|
||
|
|
||
|
stackA.pop();
|
||
|
stackB.pop();
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
module.exports = baseIsEqualDeep;
|