UNPKG

pop-compare

Version:

Polymorphic deep comparison operator for arbitrary values

79 lines (71 loc) 2.93 kB
/** Determines the order in which any two objects should be sorted by returning a number that has an analogous relationship to zero as the left value to the right. That is, if the left is "less than" the right, the returned value will be "less than" zero, where "less than" may be any other transitive relationship. <p>Arrays are compared by the first diverging values, or by length. <p>Any two values that are incomparable return zero. As such, <code>equals</code> should not be implemented with <code>compare</code> since incomparability is indistinguishable from equality. <p>Sorts strings lexicographically. This is not suitable for any particular international setting. Different locales sort their phone books in very different ways, particularly regarding diacritics and ligatures. <p>If the given object is an instance of a type that implements a method named "compare", this function defers to the instance. The method does not need to be an owned property to distinguish it from an object literal since object literals are incomparable. Unlike <code>Object</code> however, <code>Array</code> implements <code>compare</code>. @param {Any} left @param {Any} right @returns {Number} a value having the same transitive relationship to zero as the left and right values. */ module.exports = compare; function compare(a, b, compare) { var difference; // unbox objects // mercifully handles the Date case if (a && typeof a.valueOf === "function") { a = a.valueOf(); } if (b && typeof b.valueOf === "function") { b = b.valueOf(); } // x !== x is only true if x is NaN. NaN is "incomparable" and both // equivalent and incomparable values always return 0. if (a === b || a !== a || b !== b) return 0; var aType = typeof a; var bType = typeof b; if (aType === "number" && bType === "number") return a - b; if (aType === "string" && bType === "string") return a < b ? -Infinity : Infinity; // the possibility of equality elimiated above compare = compare || module.exports; if (Array.isArray(a) && Array.isArray(b)) { for (var index in a) { if (!(index in b)) { return Infinity; } else { difference = compare(a[index], b[index], compare); if (difference) { return difference; } } } for (var index in b) { if (!(index in a)) { return -Infinity; } } return a.length - b.length; } if (a && typeof a.compare === "function") return a.compare(b, compare); // not commutative, the relationship is reversed if (b && typeof b.compare === "function") return -b.compare(a, compare); return 0; }