Demystifying the Array.prototype.sort Comparator

While patching a legacy Beego dashboard I stumbled on a tiny sorting requirement that refused to cooeprate. The goal sounded trivial: given an array that mixes one-, two- and three-digit integers, keep the global ascending order but push every two-digit value to the tail.

const sample = [1, 8, 3, 11, 100, 15, 201];
// expected: [1, 3, 8, 100, 201, 11, 15]

Naïvely I wrote a comparator, ran Array.prototype.sort, and watched the result explode. Thirty minutes later I finally understood why.

The contract of the comparator

Per ECMA-262, compare(x, y) must return

  • a negative number → x precedes y
  • zero → relative order is left to the engine (do not rely on stability)
  • a positive number → y precedes x

Crucially, the engine may envoke the comparator with x and y in any order; the arguments are not guaranteed to reflect their original indices.

Partitioning the problem

We need three mutually exclusive cases:

  1. Both numbers are two-digit → ordinary ascending order.
  2. Exact one number is two-digit → the two-digit one must lose.
  3. Neither is two-digit → ordinary ascending order.

Implementation

function isTwoDigit(n) {
  return n >= 10 && n <= 99;
}

function customOrder(left, right) {
  const lTwo = isTwoDigit(left);
  const rTwo = isTwoDigit(right);

  // Case 1
  if (lTwo && rTwo) return left - right;

  // Case 2
  if (lTwo) return 1;   // left is two-digit → move right
  if (rTwo) return -1;  // right is two-digit → keep left

  // Case 3
  return left - right;
}

const data = [1, 8, 3, 11, 100, 15, 201];
data.sort(customOrder);
console.log(data); // [1, 3, 8, 100, 201, 11, 15]

The key insight: the comparator never swaps elements in place; it merely tells the engine which value should appear first in the final permutation. The actual sorting algorithm (TimSort in V8, for example) runs behind the scenes and may invoke the comparator hundreds of times for modest arrays.

Tags: javascript Array.prototype.sort comparator ecmascript TimSort

Posted on Sun, 17 May 2026 08:30:11 +0000 by dolphinsnot