Skip to content

Instantly share code, notes, and snippets.

@priezz
Created June 20, 2019 05:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save priezz/c979747123bd14ccc6aeaecdd0ade95a to your computer and use it in GitHub Desktop.
Save priezz/c979747123bd14ccc6aeaecdd0ade95a to your computer and use it in GitHub Desktop.
Objects equality deep checking
export function objectsEqual(...objects: any[]) {
let leftChain: any[]
let rightChain: any[]
const _compareTwoObjects = (x: any, y: any) => {
// 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(const p in y) {
if(y.hasOwnProperty(p)) {
if(y.hasOwnProperty(p) !== x.hasOwnProperty(p)) return false
else if(typeof y[p] !== typeof x[p]) return false
}
}
for(const p in x) {
if(x.hasOwnProperty(p)) {
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(!_compareTwoObjects(x[p], y[p])) return false
leftChain.pop()
rightChain.pop()
break
default:
if(x[p] !== y[p]) return false
break
}
}
}
return true
}
if(objects.length < 1) return true
for(let i = 1; i < objects.length; i++) {
leftChain = []
rightChain = []
if(!_compareTwoObjects(objects[0], objects[i])) return false
}
return true
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment