Skip to content

Commit

Permalink
_.isEqual improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelficarra committed Jul 15, 2011
1 parent a12d003 commit c7c57ca
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 14 deletions.
9 changes: 7 additions & 2 deletions test/objects.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ $(document).ready(function() {

var moe = {name : 'moe', lucky : [13, 27, 34]};
var clone = {name : 'moe', lucky : [13, 27, 34]};
var isEqualObj = {isEqual: function (o) { return o.isEqual == this.isEqual; }, unique: {}};
var isEqualObjClone = {isEqual: isEqualObj.isEqual, unique: {}};
ok(moe != clone, 'basic equality between objects is false');
ok(_.isEqual(moe, clone), 'deep equality is true');
ok(_(moe).isEqual(clone), 'OO-style deep equality works');
Expand All @@ -86,8 +88,11 @@ $(document).ready(function() {
ok(!_.isEqual({source: '(?:)', global: true, multiline: true, ignoreCase: true}, /(?:)/gim), 'RegExp-like objects and RegExps are not equal');
ok(!_.isEqual(null, [1]), 'a falsy is never equal to a truthy');
ok(!_.isEqual(undefined, null), '`undefined` is not equal to `null`');
ok(_.isEqual({isEqual: function () { return true; }}, {}), 'first object implements `isEqual`');
ok(_.isEqual({}, {isEqual: function () { return true; }}), 'second object implements `isEqual`');
ok(_.isEqual(isEqualObj, isEqualObj), 'both objects implement `isEqual`, same objects');
ok(_.isEqual(isEqualObj, isEqualObjClone), 'both objects implement `isEqual`, different objects');
ok(_.isEqual(isEqualObjClone, isEqualObj), 'both objects implement `isEqual`, different objects, swapped');
ok(!_.isEqual(isEqualObj, {}), 'first object implements `isEqual`');
ok(!_.isEqual({}, isEqualObj), 'second object implements `isEqual`');
ok(!_.isEqual({x: 1, y: undefined}, {x: 1, z: 2}), 'objects with the same number of undefined keys are not equal');
ok(!_.isEqual(new Foo, new Bar), 'objects with different inherited properties are not equal');
ok(!_.isEqual(_({x: 1, y: undefined}).chain(), _({x: 1, z: 2}).chain()), 'wrapped objects are not equal');
Expand Down
22 changes: 10 additions & 12 deletions underscore.js
Original file line number Diff line number Diff line change
Expand Up @@ -606,29 +606,27 @@
// The type comparison above prevents unwanted type coercion.
if (a == b) return true;
// Optimization; ensure that both values are truthy or falsy.
if ((!a && b) || (a && !b)) return false;
if (!a != !b) return false;
// `NaN` values are equal.
if (_.isNaN(a)) return _.isNaN(b);
// Compare dates by their millisecond values.
var isDateA = _.isDate(a), isDateB = _.isDate(b);
if (isDateA || isDateB) return isDateA && isDateB && a.getTime() == b.getTime();
if (_.isDate(a)) return _.isDate(b) && a.getTime() == b.getTime();
// Compare RegExps by their source patterns and flags.
var isRegExpA = _.isRegExp(a), isRegExpB = _.isRegExp(b);
if (isRegExpA || isRegExpB) return isRegExpA && isRegExpB &&
a.source == b.source &&
a.global == b.global &&
a.multiline == b.multiline &&
a.ignoreCase == b.ignoreCase;
if (_.isRegExp(a))
return _.isRegExp(b) &&
a.source == b.source &&
a.global == b.global &&
a.multiline == b.multiline &&
a.ignoreCase == b.ignoreCase;
// Ensure that both values are objects.
if (typeA != 'object') return false;
// Unwrap any wrapped objects.
if (a._chain) a = a._wrapped;
if (b._chain) b = b._wrapped;
// Invoke a custom `isEqual` method if one is provided.
if (a.isEqual) return a.isEqual(b);
if (b.isEqual) return b.isEqual(a);
if (typeof a.isEqual == 'function') return a.isEqual(b);
// Compare array lengths to determine if a deep comparison is necessary.
if (a.length && (a.length !== b.length)) return false;
if ('length' in a && (a.length !== b.length)) return false;
// Assume equality for cyclic structures.
var length = stack.length;
while (length--) {
Expand Down

0 comments on commit c7c57ca

Please sign in to comment.