Skip to content

Commit ec1cf9c

Browse files
committed
[Breaking] non-Date objects with different [[Prototypes]] are not equal
Date objects are equal when: - the timestamp is the same - if strict, the [[Prototype]] is the same - own properties match, same as normal objects
1 parent 99a7761 commit ec1cf9c

File tree

2 files changed

+55
-6
lines changed

2 files changed

+55
-6
lines changed

index.js

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ var isArguments = require('is-arguments');
33
var is = require('object-is');
44
var isRegex = require('is-regex');
55
var flags = require('regexp.prototype.flags');
6-
76
var isArray = require('isarray');
87
var isDate = require('is-date-object');
98

109
var getTime = Date.prototype.getTime;
10+
var gPO = Object.getPrototypeOf;
1111

1212
function deepEqual(actual, expected, options) {
1313
var opts = options || {};
@@ -52,7 +52,7 @@ function isBuffer(x) {
5252
}
5353

5454
function objEquiv(a, b, opts) {
55-
/* eslint max-statements: [2, 50] */
55+
/* eslint max-statements: [2, 60] */
5656
var i, key;
5757
if (isUndefinedOrNull(a) || isUndefinedOrNull(b)) { return false; }
5858

@@ -72,9 +72,13 @@ function objEquiv(a, b, opts) {
7272
return a.source === b.source && flags(a) === flags(b);
7373
}
7474

75-
if (isDate(a) && isDate(b)) {
76-
return getTime.call(a) === getTime.call(b);
77-
}
75+
var aIsDate = isDate(a);
76+
var bIsDate = isDate(b);
77+
if (aIsDate !== bIsDate) { return false; }
78+
if (aIsDate || bIsDate) { // && would work too, because both are true or both false here
79+
if (getTime.call(a) !== getTime.call(b)) { return false; }
80+
if (opts.strict && gPO && gPO(a) !== gPO(b)) { return false; }
81+
} else if (gPO && gPO(a) !== gPO(b)) { return false; } // non-Dates always compare [[Prototype]]s
7882

7983
var aIsBuffer = isBuffer(a);
8084
var bIsBuffer = isBuffer(b);

test/cmp.js

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,19 @@ test('arguments class', function (t) {
6666
test('dates', function (t) {
6767
var d0 = new Date(1387585278000);
6868
var d1 = new Date('Fri Dec 20 2013 16:21:18 GMT-0800 (PST)');
69-
t.ok(equal(d0, d1));
69+
70+
t.ok(equal(d0, d1), 'two dates with the same timestamp are equal');
71+
t.ok(equal(d1, d0), 'two dates with the same timestamp are equal');
72+
t.ok(equal(d0, d1, { strict: true }), 'strict: two dates with the same timestamp are equal');
73+
t.ok(equal(d1, d0, { strict: true }), 'strict: two dates with the same timestamp are equal');
74+
75+
d1.a = true;
76+
77+
t.notOk(equal(d0, d1), 'two dates with the same timestamp but different own properties are not equal');
78+
t.notOk(equal(d1, d0), 'two dates with the same timestamp but different own properties are not equal');
79+
t.notOk(equal(d0, d1, { strict: true }), 'strict: two dates with the same timestamp but different own properties are not equal');
80+
t.notOk(equal(d1, d0, { strict: true }), 'strict: two dates with the same timestamp but different own properties are not equal');
81+
7082
t.end();
7183
});
7284

@@ -316,3 +328,36 @@ test('arrays and objects', function (t) {
316328

317329
t.end();
318330
});
331+
332+
test('[[Prototypes]]', { skip: !Object.getPrototypeOf }, function (t) {
333+
function C() {}
334+
var instance = new C();
335+
delete instance.constructor;
336+
337+
t.notOk(equal({}, instance), 'two identical objects with different [[Prototypes]] are not equal');
338+
t.notOk(equal({}, instance, { strict: true }), 'strict: two identical objects with different [[Prototypes]] are not equal');
339+
340+
t.test('Dates with different prototypes', { skip: !Object.setPrototypeOf }, function (st) {
341+
var d1 = new Date(0);
342+
var d2 = new Date(0);
343+
344+
st.ok(equal(d1, d2), 'two dates with the same timestamp are equal');
345+
st.ok(equal(d2, d1), 'two dates with the same timestamp are equal');
346+
st.ok(equal(d1, d2, { strict: true }), 'strict: two dates with the same timestamp are equal');
347+
st.ok(equal(d1, d1, { strict: true }), 'strict: two dates with the same timestamp are equal');
348+
349+
var newProto = {};
350+
Object.setPrototypeOf(newProto, Date.prototype);
351+
Object.setPrototypeOf(d2, newProto);
352+
st.ok(d2 instanceof Date, 'd2 is still a Date instance');
353+
354+
st.ok(equal(d1, d2), 'two dates with the same timestamp and different [[Prototype]] are equal');
355+
st.ok(equal(d2, d1), 'two dates with the same timestamp and different [[Prototype]] are equal');
356+
st.notOk(equal(d1, d2, { strict: true }), 'strict: two dates with the same timestamp and different [[Prototype]] are not equal');
357+
st.notOk(equal(d2, d1, { strict: true }), 'strict: two dates with the same timestamp and different [[Prototype]] are not equal');
358+
359+
st.end();
360+
});
361+
362+
t.end();
363+
});

0 commit comments

Comments
 (0)