Skip to content

deepEqual is incorrect when there are inherited properties #24

@jordanhendricks

Description

@jordanhendricks

I used deepEqual to compare two objects with the same constructor, with the same arguments (which in this constructor, would result in the same keys on the instantiated object). To my surprise, deepEqual returned false for these objects.

The problem was that deepEqual saw a toString function on one object, but not the other. The toString function lives on the prototype chain of the constructor, and given that the objects had the same constructor, I would expect them to be the same.

The problem seems to be in this code:

...
	for (k in obj1) {
		if (!obj2.hasOwnProperty(k))
			return (false);
...

The for (k in obj1) loop will iterate over all keys on obj1 all the way up its prototype chain. But the next statement checks if a key is found on obj2 via hasOwnProperty, which only checks against keys on the bottom level of the chain. The set of keys being compared in these two objects is not the same.

Here is a simplified version of the program I ran that illustrates this issue:

var jsprim = require('jsprim');

function Foo(arg) {
    this.arg = arg;
};
Foo.prototype.toString = function toString() {
    return (this.args.toString());
}

function Bar(arg) {
    this.arg = arg;
};

var f1 = new Foo('foo');
var f2 = new Foo('foo');
var b1 = new Bar('bar');
var b2 = new Bar('bar');

console.log('f1 and f2 equal?: ', jsprim.deepEqual(f1, f2));
console.log('f1.toString and f2.toString equal?: ', jsprim.deepEqual(f1.toString,
    f2.toString));

console.log('b1 and b2 equal?: ', jsprim.deepEqual(b1, b2));

When run, this program outputs:

$ node deepequal-test.js
f1 and f2 equal?:  false
f1.toString and f2.toString equal?:  true
b1 and b2 equal?:  true

I think this can be fixed by iterating over the keys returned by Object.keys instead. The Object.keys method only returns an object's own enumerable properties, excluding those higher in the prototype chain. Given that deepEqual also checks that two objects were created with the same constructor, this is sufficient for verifying equality.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions