function equal(a, b) {
if (a === b) return true;
if (a && b && typeof a == 'object' && typeof b == 'object') {
if (a.constructor !== b.constructor) return false;
var length, i, keys;
if (Array.isArray(a)) {
length = a.length;
if (length != b.length) return false;
for (i = length; i-- !== 0;)
if (!equal(a[i], b[i])) return false;
return true;
}
if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;
if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();
if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();
keys = Object.keys(a);
length = keys.length;
if (length !== Object.keys(b).length) return false;
for (i = length; i-- !== 0;)
if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;
for (i = length; i-- !== 0;) {
var key = keys[i];
if (!equal(a[key], b[key])) return false;
}
return true;
}
return a !== a && b !== b;
};
const isUndefined = v => v === undefined
const table = new WeakMap();
let counter = 0;
const stableHash = (arg) => {
const type = typeof arg;
const constructor = arg && arg.constructor;
const isDate = constructor == Date;
let result;
let index;
if (Object(arg) === arg && !isDate && constructor != RegExp) {
result = table.get(arg);
if (result) return result;
result = ++counter + '~';
table.set(arg, result);
if (constructor == Array) {
result = '@';
for (index = 0; index < arg.length; index++) {
result += stableHash(arg[index]) + ',';
}
table.set(arg, result);
}
if (constructor == Object) {
result = '#';
const keys = Object.keys(arg).sort();
while (!isUndefined(index = keys.pop())) {
if (!isUndefined(arg[index])) {
result += index + ':' + stableHash(arg[index]) + ',';
}
}
table.set(arg, result);
}
} else {
result = isDate ? arg.toJSON() : type == 'symbol' ? arg.toString() : type == 'string' ? JSON.stringify(arg) : '' + arg;
}
return result;
};
function compare(currentData, newData) {
return stableHash(currentData) == stableHash(newData)
}
var data = [{
description: 'equal numbers',
value1: 1,
value2: 1,
equal: true,
},
{
description: 'not equal numbers',
value1: 1,
value2: 2,
equal: false,
},
{
description: 'number and array are not equal',
value1: 1,
value2: [],
equal: false,
},
{
description: '0 and null are not equal',
value1: 0,
value2: null,
equal: false,
},
{
description: 'equal strings',
value1: 'a',
value2: 'a',
equal: true,
},
{
description: 'big object',
value1: {
prop1: 'value1',
prop2: 'value2',
prop3: 'value3',
prop4: {
subProp1: 'sub value1',
subProp2: {
subSubProp1: 'sub sub value1',
subSubProp2: [
1,
2,
{
prop2: 1,
prop: 2
},
4,
5,
],
},
},
prop5: 1000,
prop6: new Date(2016, 2, 10),
},
value2: {
prop5: 1000,
prop3: 'value3',
prop1: 'value1',
prop2: 'value2',
prop6: new Date('2016/03/10'),
prop4: {
subProp2: {
subSubProp1: 'sub sub value1',
subSubProp2: [
1,
2,
{
prop2: 1,
prop: 2
},
4,
5,
],
},
subProp1: 'sub value1',
},
},
equal: true,
},
];