SO Answer

Question: Resort array of objects on another key without disturbing previous sorting (part-sorting) in JavaScript #2.

by KooiInc MeHere

HTML

<script src="https://cdn.jsdelivr.net/gh/KooiInc/JSHelpers/Helpers.min.js"></script>
<div class="solink" data-linkid="25157510">
    <div class="linkhover">loading....</div>
</div>
<div id="result">
  <code>data</code> ordered by Rate 
  <i>and</i> Price descending 
  (using <code>xSort.orderBy)</code>
</div>
<pre></pre>

JavaScript

// Sort an array of objects interdependent on one or more of
// its key values. The initial array will not be mutated,
// unless you re-assign it
//
// syntax
// ------
// const sorted = XSort().create([arrOfObjects])
//  .orderBy(
//		{key: [keyname], [descending=0/1] }, 
//		{key: [keyname], [descending=0/1]} );
// Can use lambda methods for the keys that should be sorted
// so if the value is an object, something like
//   [xsort].orderBy({key => key.firstName.startsWith("J")}, {[...]}, ...)
( d => {
	const booksArray = getData();
  const booksSorted = XSort()
      .create(booksArray)
      .orderBy( { key: 'Rate' }, { key: 'Price', descending: 1 } );
  
  d.querySelector("pre").textContent = JSON.stringify( booksSorted, 	null, " " );
  
  function XSort() {
    const multiSorter = sortKeys => {
      if (!sortKeys || sortKeys[0].constructor !== Object) {
        throw new TypeError("Provide at least one {key: [keyname]} to sort on");
      }
            
      return function (val0, val1) {
        for (let sortKey of sortKeys) {
          const v0 = sortKey.key instanceof Function ? sortKey.key(val0) : val0[sortKey.key];
          const v1 = sortKey.key instanceof Function ? sortKey.key(val1) : val1[sortKey.key];
          const isString = v0.constructor === String || v1.constructor === String;
          const compare = sortKey.descending ?
            isString ? v1.toLowerCase().localeCompare(v0.toLowerCase()) : v1 - v0 :
            isString ? v0.toLowerCase().localeCompare(v1.toLowerCase()) : v0 - v1;
          if ( compare !== 0 ) { return compare; }
        }
      };
    }
    const Sorter = function (array) {
      this.array = array;
    };
    
    Sorter.prototype = {
      orderBy: function(...sortOns) {
        return this.array.slice().sort(multiSorter(sortOns));
      },
    };

    return {
      create: array => new Sorter(array)
    };
  }

  function getData() {
    return [
      {Rate:3, Id:16, Price:200, Name:"Functional Programming"},
...