/*! * @license ObjectComparator * Copyright © 2012 Joel Purra * Released under MIT, BSD and GPL license. Comply with at least one. * * A javascript plugin to create a comparator for one or more properties of an object. * Comparators are useful for sorting arrays of objects, and for general comparisons * in, for example, if statements. * The comparison is done only if the types of both objects' property matches. */ // https://gist.github.com/2984763 // // USAGE // var comparator = JoelPurra.createComparator("propertyName"); // var reverseComparator = JoelPurra.createComparator("!propertyName"); // var comparators = JoelPurra.createComparators(["propertyName1", "propertyName2"]); // var mixedComparators = JoelPurra.createComparators(["propertyName1", "!propertyName2"]); // EXAMPLE // var people = [ // // Age in years, length in centimeters // { name: "John", age: 30, height: 187 }, // { name: "Bilbo", age: 111, height: 112 }, // { name: "Jane", age: 30, height: 165 }, // { name: "Gollum", age: 570, height: 112 } // ]; // // Sort by height (ascending) only // var shortToLongComparator = JoelPurra.createComparator("height"); // people.sort(shortToLongComparator); // // => Bilbo, Gollum, Jane, John // // Sort by height (ascending) and age (descending) // var shortToLongOldToYoungComparator = JoelPurra.createComparators(["height", "!age"]); // people.sort(shortToLongOldToYoungComparator); // => Gollum, Bilbo, Jane, John // /*jslint white: true*/ // Set up namespace, if needed var JoelPurra = JoelPurra || {}; (function(namespace) { "use strict"; // jshint ;_; namespace.createNormalComparator = function(property) { // This comparison is not as relaxed as normal comparisons. The type is checked first, and it has // to match in order to continue. // // https://developer.mozilla.org/en/JavaScript/Guide/Expressions_and_Operators#Comparison_operators // "The operands can be numerical, string, logical, or object values. // Strings are compared based on standard lexicographical ordering, using Unicode values. // In most cases, if the two operands are not of the same type, JavaScript attempts to convert // the operands to an appropriate type for the comparison." return function(a, b) { if (typeof(a) !== typeof(b)) { throw new Error("object property \"" + property + "\" was not of the same type in a and b."); } // Using strict comparison now that the object types are the same if (a[property] === b[property]) { return 0; } if (a[property] < b[property]) { return -1; } if (a[property] > b[property]) { return 1; } throw new Error("Could not compare objects and find a matching result"); }; }; namespace.createReverseComparator = function(property) { // Calling the parent function actually allows for properties like // "!!age" for "reverse reverse age comparator" ;) var comparator = namespace.createComparator(property); return function(a, b) { return comparator(b, a); }; }; namespace.createComparator = function(property) { var comparator; if (property.substring(0, 1) === "!") { property = property.substring(1); comparator = namespace.createReverseComparator(property); } else { comparator = namespace.createNormalComparator(property); } return comparator; }; namespace.createComparators = function(properties) { var comparators = [], i; for (i = 0; i < properties.length; i += 1) { comparators.push(namespace.createComparator(properties[i])); } return function(a, b) { var result = 0, i, comparator; for (i = 0; i < comparators.length; i += 1) { comparator = comparators[i]; result = comparator(a, b); if (result !== 0) { break; } } return result; }; }; }(JoelPurra));