From 365eea6aa7570b738850a1652fdd51b13208fef9 Mon Sep 17 00:00:00 2001 From: Kit Goncharov Date: Wed, 13 Jul 2011 10:48:16 -0600 Subject: [PATCH] `_.isEqual`: Streamline the deep comparison algorithm and remove the dependency on `_.keys`. --- test/objects.js | 6 ++++++ underscore.js | 15 ++++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/test/objects.js b/test/objects.js index c32a13ad7..08206b913 100644 --- a/test/objects.js +++ b/test/objects.js @@ -65,6 +65,11 @@ $(document).ready(function() { }); test("objects: isEqual", function() { + function Foo(){ this.own = 'a'; } + function Bar(){ this.own = 'a'; } + Foo.prototype.inherited = 1; + Bar.prototype.inherited = 2; + var moe = {name : 'moe', lucky : [13, 27, 34]}; var clone = {name : 'moe', lucky : [13, 27, 34]}; ok(moe != clone, 'basic equality between objects is false'); @@ -80,6 +85,7 @@ $(document).ready(function() { ok(_.isEqual({isEqual: function () { return true; }}, {}), 'first object implements `isEqual`'); ok(_.isEqual({}, {isEqual: function () { return true; }}), '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'); equals(_({x: 1, y: 2}).chain().isEqual(_({x: 1, y: 2}).chain()).value(), true, 'wrapped objects are equal'); diff --git a/underscore.js b/underscore.js index 1a68a9784..14d5c01ed 100644 --- a/underscore.js +++ b/underscore.js @@ -632,14 +632,19 @@ // Add the object to the stack of traversed objects. stack.push(a); // Deep compare the contents. - var aKeys = _.keys(a), bKeys = _.keys(b); + var size = 0, sizeRight = 0, result = true, key; + for (key in a) { + // Count the expected number of properties. + size++; + // Deep compare each member. + if (!(result = key in b && eq(a[key], b[key], stack))) break; + } // Ensure that both objects contain the same number of properties. - var result = aKeys.length == bKeys.length; if (result) { - // Recursively compare properties. - for (var key in a) { - if (!(result = key in b && eq(a[key], b[key], stack))) break; + for (key in b) { + if (++sizeRight > size) break; } + result = size == sizeRight; } // Remove the object from the stack of traversed objects. stack.pop();