_equalObjects.js
 1  var getAllKeys = require('./_getAllKeys');
 2  
 3  /** Used to compose bitmasks for value comparisons. */
 4  var COMPARE_PARTIAL_FLAG = 1;
 5  
 6  /** Used for built-in method references. */
 7  var objectProto = Object.prototype;
 8  
 9  /** Used to check objects for own properties. */
10  var hasOwnProperty = objectProto.hasOwnProperty;
11  
12  /**
13   * A specialized version of `baseIsEqualDeep` for objects with support for
14   * partial deep comparisons.
15   *
16   * @private
17   * @param {Object} object The object to compare.
18   * @param {Object} other The other object to compare.
19   * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
20   * @param {Function} customizer The function to customize comparisons.
21   * @param {Function} equalFunc The function to determine equivalents of values.
22   * @param {Object} stack Tracks traversed `object` and `other` objects.
23   * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
24   */
25  function equalObjects(object, other, bitmask, customizer, equalFunc, stack) {
26    var isPartial = bitmask & COMPARE_PARTIAL_FLAG,
27        objProps = getAllKeys(object),
28        objLength = objProps.length,
29        othProps = getAllKeys(other),
30        othLength = othProps.length;
31  
32    if (objLength != othLength && !isPartial) {
33      return false;
34    }
35    var index = objLength;
36    while (index--) {
37      var key = objProps[index];
38      if (!(isPartial ? key in other : hasOwnProperty.call(other, key))) {
39        return false;
40      }
41    }
42    // Check that cyclic values are equal.
43    var objStacked = stack.get(object);
44    var othStacked = stack.get(other);
45    if (objStacked && othStacked) {
46      return objStacked == other && othStacked == object;
47    }
48    var result = true;
49    stack.set(object, other);
50    stack.set(other, object);
51  
52    var skipCtor = isPartial;
53    while (++index < objLength) {
54      key = objProps[index];
55      var objValue = object[key],
56          othValue = other[key];
57  
58      if (customizer) {
59        var compared = isPartial
60          ? customizer(othValue, objValue, key, other, object, stack)
61          : customizer(objValue, othValue, key, object, other, stack);
62      }
63      // Recursively compare objects (susceptible to call stack limits).
64      if (!(compared === undefined
65            ? (objValue === othValue || equalFunc(objValue, othValue, bitmask, customizer, stack))
66            : compared
67          )) {
68        result = false;
69        break;
70      }
71      skipCtor || (skipCtor = key == 'constructor');
72    }
73    if (result && !skipCtor) {
74      var objCtor = object.constructor,
75          othCtor = other.constructor;
76  
77      // Non `Object` object instances with different constructors are not equal.
78      if (objCtor != othCtor &&
79          ('constructor' in object && 'constructor' in other) &&
80          !(typeof objCtor == 'function' && objCtor instanceof objCtor &&
81            typeof othCtor == 'function' && othCtor instanceof othCtor)) {
82        result = false;
83      }
84    }
85    stack['delete'](object);
86    stack['delete'](other);
87    return result;
88  }
89  
90  module.exports = equalObjects;