Skip to content

Instantly share code, notes, and snippets.

@wrick17
Created April 3, 2017 15:34
Show Gist options
  • Save wrick17/e6fdc7206fa901efe86248b0e4c3eaaf to your computer and use it in GitHub Desktop.
Save wrick17/e6fdc7206fa901efe86248b0e4c3eaaf to your computer and use it in GitHub Desktop.
Gist file for comparing two objects
function deepCompare () {
var i, l, leftChain, rightChain;
function compare2Objects (x, y) {
var p;
// remember that NaN === NaN returns false
// and isNaN(undefined) returns true
if (isNaN(x) && isNaN(y) && typeof x === 'number' && typeof y === 'number') {
return true;
}
// Compare primitives and functions.
// Check if both arguments link to the same object.
// Especially useful on the step where we compare prototypes
if (x === y) {
return true;
}
// Works in case when functions are created in constructor.
// Comparing dates is a common scenario. Another built-ins?
// We can even handle functions passed across iframes
if ((typeof x === 'function' && typeof y === 'function') ||
(x instanceof Date && y instanceof Date) ||
(x instanceof RegExp && y instanceof RegExp) ||
(x instanceof String && y instanceof String) ||
(x instanceof Number && y instanceof Number)) {
return x.toString() === y.toString();
}
// At last checking prototypes as good as we can
if (!(x instanceof Object && y instanceof Object)) {
return false;
}
if (x.isPrototypeOf(y) || y.isPrototypeOf(x)) {
return false;
}
if (x.constructor !== y.constructor) {
return false;
}
if (x.prototype !== y.prototype) {
return false;
}
// Check for infinitive linking loops
if (leftChain.indexOf(x) > -1 || rightChain.indexOf(y) > -1) {
return false;
}
// Quick checking of one object being a subset of another.
// todo: cache the structure of arguments[0] for performance
for (p in y) {
if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) {
return false;
}
else if (typeof y[p] !== typeof x[p]) {
return false;
}
}
for (p in x) {
if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) {
return false;
}
else if (typeof y[p] !== typeof x[p]) {
return false;
}
switch (typeof (x[p])) {
case 'object':
case 'function':
leftChain.push(x);
rightChain.push(y);
if (!compare2Objects (x[p], y[p])) {
return false;
}
leftChain.pop();
rightChain.pop();
break;
default:
if (x[p] !== y[p]) {
return false;
}
break;
}
}
return true;
}
if (arguments.length < 1) {
return true; //Die silently? Don't know how to handle such case, please help...
// throw "Need two or more arguments to compare";
}
for (i = 1, l = arguments.length; i < l; i++) {
leftChain = []; //Todo: this can be cached
rightChain = [];
if (!compare2Objects(arguments[0], arguments[i])) {
return false;
}
}
return true;
}
function deepCompare(){function t(e,r){var f;if(isNaN(e)&&isNaN(r)&&"number"==typeof e&&"number"==typeof r)return!0;if(e===r)return!0;if("function"==typeof e&&"function"==typeof r||e instanceof Date&&r instanceof Date||e instanceof RegExp&&r instanceof RegExp||e instanceof String&&r instanceof String||e instanceof Number&&r instanceof Number)return e.toString()===r.toString();if(!(e instanceof Object&&r instanceof Object))return!1;if(e.isPrototypeOf(r)||r.isPrototypeOf(e))return!1;if(e.constructor!==r.constructor)return!1;if(e.prototype!==r.prototype)return!1;if(n.indexOf(e)>-1||o.indexOf(r)>-1)return!1;for(f in r){if(r.hasOwnProperty(f)!==e.hasOwnProperty(f))return!1;if(typeof r[f]!=typeof e[f])return!1}for(f in e){if(r.hasOwnProperty(f)!==e.hasOwnProperty(f))return!1;if(typeof r[f]!=typeof e[f])return!1;switch(typeof e[f]){case"object":case"function":if(n.push(e),o.push(r),!t(e[f],r[f]))return!1;n.pop(),o.pop();break;default:if(e[f]!==r[f])return!1}}return!0}var e,r,n,o;if(arguments.length<1)return!0;for(e=1,r=arguments.length;r>e;e++)if(n=[],o=[],!t(arguments[0],arguments[e]))return!1;return!0}
@wrick17
Copy link
Author

wrick17 commented Apr 3, 2017

Really useful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment