UNPKG

@segment/equals

Version:

Check if two values are deeply equivalent

122 lines (100 loc) 2.6 kB
var type = require('jkroso-type') // (any, any, [array]) -> boolean function equal(a, b, memos){ // All identical values are equivalent if (a === b) return true var fnA = types[type(a)] var fnB = types[type(b)] return fnA && fnA === fnB ? fnA(a, b, memos) : false } var types = {} // (Number) -> boolean types.number = function(a, b){ return a !== a && b !== b/*Nan check*/ } // (function, function, array) -> boolean types['function'] = function(a, b, memos){ return a.toString() === b.toString() // Functions can act as objects && types.object(a, b, memos) && equal(a.prototype, b.prototype) } // (date, date) -> boolean types.date = function(a, b){ return +a === +b } // (regexp, regexp) -> boolean types.regexp = function(a, b){ return a.toString() === b.toString() } // (DOMElement, DOMElement) -> boolean types.element = function(a, b){ return a.outerHTML === b.outerHTML } // (textnode, textnode) -> boolean types.textnode = function(a, b){ return a.textContent === b.textContent } // decorate `fn` to prevent it re-checking objects // (function) -> function function memoGaurd(fn){ return function(a, b, memos){ if (!memos) return fn(a, b, []) var i = memos.length, memo while (memo = memos[--i]) { if (memo[0] === a && memo[1] === b) return true } return fn(a, b, memos) } } types['arguments'] = types['bit-array'] = types.array = memoGaurd(arrayEqual) // (array, array, array) -> boolean function arrayEqual(a, b, memos){ var i = a.length if (i !== b.length) return false memos.push([a, b]) while (i--) { if (!equal(a[i], b[i], memos)) return false } return true } types.object = memoGaurd(objectEqual) // (object, object, array) -> boolean function objectEqual(a, b, memos) { if (typeof a.equal == 'function') { memos.push([a, b]) return a.equal(b, memos) } var ka = getEnumerableProperties(a) var kb = getEnumerableProperties(b) var i = ka.length // same number of properties if (i !== kb.length) return false // although not necessarily the same order ka.sort() kb.sort() // cheap key test while (i--) if (ka[i] !== kb[i]) return false // remember memos.push([a, b]) // iterate again this time doing a thorough check i = ka.length while (i--) { var key = ka[i] if (!equal(a[key], b[key], memos)) return false } return true } // (object) -> array function getEnumerableProperties (object) { var result = [] for (var k in object) if (k !== 'constructor') { result.push(k) } return result } module.exports = equal