baseIsEqualDeep.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. var equalArrays = require('./equalArrays'),
  2. equalByTag = require('./equalByTag'),
  3. equalObjects = require('./equalObjects'),
  4. isArray = require('../lang/isArray'),
  5. isTypedArray = require('../lang/isTypedArray');
  6. /** `Object#toString` result references. */
  7. var argsTag = '[object Arguments]',
  8. arrayTag = '[object Array]',
  9. objectTag = '[object Object]';
  10. /** Used for native method references. */
  11. var objectProto = Object.prototype;
  12. /** Used to check objects for own properties. */
  13. var hasOwnProperty = objectProto.hasOwnProperty;
  14. /**
  15. * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
  16. * of values.
  17. */
  18. var objToString = objectProto.toString;
  19. /**
  20. * A specialized version of `baseIsEqual` for arrays and objects which performs
  21. * deep comparisons and tracks traversed objects enabling objects with circular
  22. * references to be compared.
  23. *
  24. * @private
  25. * @param {Object} object The object to compare.
  26. * @param {Object} other The other object to compare.
  27. * @param {Function} equalFunc The function to determine equivalents of values.
  28. * @param {Function} [customizer] The function to customize comparing objects.
  29. * @param {boolean} [isLoose] Specify performing partial comparisons.
  30. * @param {Array} [stackA=[]] Tracks traversed `value` objects.
  31. * @param {Array} [stackB=[]] Tracks traversed `other` objects.
  32. * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
  33. */
  34. function baseIsEqualDeep(object, other, equalFunc, customizer, isLoose, stackA, stackB) {
  35. var objIsArr = isArray(object),
  36. othIsArr = isArray(other),
  37. objTag = arrayTag,
  38. othTag = arrayTag;
  39. if (!objIsArr) {
  40. objTag = objToString.call(object);
  41. if (objTag == argsTag) {
  42. objTag = objectTag;
  43. } else if (objTag != objectTag) {
  44. objIsArr = isTypedArray(object);
  45. }
  46. }
  47. if (!othIsArr) {
  48. othTag = objToString.call(other);
  49. if (othTag == argsTag) {
  50. othTag = objectTag;
  51. } else if (othTag != objectTag) {
  52. othIsArr = isTypedArray(other);
  53. }
  54. }
  55. var objIsObj = objTag == objectTag,
  56. othIsObj = othTag == objectTag,
  57. isSameTag = objTag == othTag;
  58. if (isSameTag && !(objIsArr || objIsObj)) {
  59. return equalByTag(object, other, objTag);
  60. }
  61. if (!isLoose) {
  62. var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),
  63. othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');
  64. if (objIsWrapped || othIsWrapped) {
  65. return equalFunc(objIsWrapped ? object.value() : object, othIsWrapped ? other.value() : other, customizer, isLoose, stackA, stackB);
  66. }
  67. }
  68. if (!isSameTag) {
  69. return false;
  70. }
  71. // Assume cyclic values are equal.
  72. // For more information on detecting circular references see https://es5.github.io/#JO.
  73. stackA || (stackA = []);
  74. stackB || (stackB = []);
  75. var length = stackA.length;
  76. while (length--) {
  77. if (stackA[length] == object) {
  78. return stackB[length] == other;
  79. }
  80. }
  81. // Add `object` and `other` to the stack of traversed objects.
  82. stackA.push(object);
  83. stackB.push(other);
  84. var result = (objIsArr ? equalArrays : equalObjects)(object, other, equalFunc, customizer, isLoose, stackA, stackB);
  85. stackA.pop();
  86. stackB.pop();
  87. return result;
  88. }
  89. module.exports = baseIsEqualDeep;