Skip to content

Commit ab8a9b3

Browse files
committed
Assert: Revert change in how deepEqual treats imposter objects
As part of #1700, there was an inintended change to how we compare constructors. Instead of comparing `obj.constructor` of the actual value, we started comparing the constructor property as it exists on the prototype before the constructor function runs, and thus also before any after-the-fact mutation to an object property. Undo that part of the change and add a regression test. Fixes #1706.
1 parent a10122c commit ab8a9b3

2 files changed

Lines changed: 36 additions & 1 deletion

File tree

src/equiv.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ function getConstructor (obj) {
3131
//
3232
// Allow objects with no prototype, from Object.create(null), to be equivalent to
3333
// plain objects that have Object as their constructor.
34-
return !proto || proto.constructor === null ? Object : proto.constructor;
34+
return !proto || proto.constructor === null ? Object : obj.constructor;
3535
}
3636

3737
function getRegExpFlags (regexp) {

test/main/deepEqual.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1310,6 +1310,41 @@ QUnit.test('Prototypal inheritance', function (assert) {
13101310
assert.equal(QUnit.equiv(function () {}, function () {}), false);
13111311
});
13121312

1313+
QUnit.test('Prototypal inheritance imposter', function (assert) {
1314+
// Bar is a subclass of Foo that very loosely tries to hide itself
1315+
// as intermediary prototype by not adding or overriding any methods
1316+
// and not adding or overriding any instance properties, except to
1317+
// assign obj.constructor as Foo.
1318+
//
1319+
// This is a regression test for https://github.com/qunitjs/qunit/issues/1706.
1320+
//
1321+
// We may change this behaviour in a future major version, but for now
1322+
// ensure the behaviour does not change unintentionally.
1323+
//
1324+
// This difference has very low impact, given that any added methods
1325+
// or properties will result in non-equality regardless of
1326+
// obj.constructor being equal given that equiv() iterates and
1327+
// compares all own and inherited properties in a single pass.
1328+
// The only observable difference would be `instanceof` (in one
1329+
// direction) and possibly presence of non-enumerable properties.
1330+
function Foo (id) {
1331+
this.id = id;
1332+
1333+
// Make subclass Bar pretend to be Foo in terms of obj.constructor,
1334+
// thus very loosely hiding that it is an intermediary prototype.
1335+
this.constructor = Foo;
1336+
}
1337+
Foo.prototype.constructor = Foo;
1338+
1339+
function Bar (id) {
1340+
Foo.call(this, id);
1341+
}
1342+
Bar.prototype = Object.create(Foo.prototype);
1343+
Bar.prototype.constructor = Bar;
1344+
1345+
assert.deepEqual(new Foo(4), new Bar(4));
1346+
});
1347+
13131348
QUnit.test('Instances', function (assert) {
13141349
var a1, a2, b1, b2, c1, c2, c3, car, carSame, carDiff, human;
13151350

0 commit comments

Comments
 (0)