DEV Community

Cover image for Creating a Merge Sort Array Prototype for Nested Objects, Strings, and Numbers in JavaScript
Sanu Khan
Sanu Khan

Posted on

Creating a Merge Sort Array Prototype for Nested Objects, Strings, and Numbers in JavaScript

Learn how to extend JavaScript's Array prototype with a powerful and flexible merge sort function that supports nested objects, strings, and numbers.

๐Ÿง  Creating a Merge Sort Array Prototype for Nested Objects, Strings, and Numbers

Sorting arrays is easy โ€” until you need to sort deeply nested objects, ensure stable results, or avoid mutating the original array.

In this post, youโ€™ll learn how to create a powerful, non-mutating mergeSortBy() function on the Array.prototype that supports:

  • โœ… Numbers
  • โœ… Strings (case-insensitive)
  • โœ… Complex nested object keys (e.g., "user.address.city")
  • โœ… Custom comparator functions

Image description


๐Ÿ” Why Not Just Use .sort()?

Feature Array.sort() mergeSortBy() (Custom)
Mutates original array? โœ… Yes โŒ No
Stable sort? โŒ Not guaranteed before ES10 โœ… Always
Deep key sorting? โŒ No โœ… Yes
Supports custom comparator? โœ… Yes โœ… Yes

๐Ÿ”„ Step 1: Get Nested Values

function getValue(obj, path) {
  return path.split('.').reduce((acc, key) => acc?.[key], obj);
}
Enter fullscreen mode Exit fullscreen mode

๐Ÿงฎ Step 2: Comparator Helper

function defaultComparator(a, b) {
  if (a == null && b != null) return -1;
  if (a != null && b == null) return 1;
  if (typeof a === 'string' && typeof b === 'string') {
    return a.localeCompare(b);
  }
  return a > b ? 1 : a < b ? -1 : 0;
}
Enter fullscreen mode Exit fullscreen mode

๐Ÿงฉ Step 3: mergeSortBy on Array.prototype

if (!Array.prototype.mergeSortBy) {
  Array.prototype.mergeSortBy = function (keyOrFn) {
    const getComparator = () => {
      if (typeof keyOrFn === 'function') return keyOrFn;
      if (typeof keyOrFn === 'string') {
        return (a, b) =>
          defaultComparator(getValue(a, keyOrFn), getValue(b, keyOrFn));
      }
      return defaultComparator;
    };

    const merge = (left, right, comparator) => {
      const result = [];
      let i = 0, j = 0;
      while (i < left.length && j < right.length) {
        result.push(
          comparator(left[i], right[j]) <= 0 ? left[i++] : right[j++]
        );
      }
      return result.concat(left.slice(i), right.slice(j));
    };

    const mergeSort = (arr, comparator) => {
      if (arr.length <= 1) return arr;
      const mid = Math.floor(arr.length / 2);
      const left = mergeSort(arr.slice(0, mid), comparator);
      const right = mergeSort(arr.slice(mid), comparator);
      return merge(left, right, comparator);
    };

    return mergeSort(this.slice(), getComparator()); // non-mutating
  };
}
Enter fullscreen mode Exit fullscreen mode

๐Ÿงช Test Cases & Real Examples

โœ… 1. Sort numbers

[9, 1, 4, 7].mergeSortBy(); // [1, 4, 7, 9]
Enter fullscreen mode Exit fullscreen mode

โœ… 2. Sort strings

["banana", "Apple", "cherry"].mergeSortBy();
// Output: ['Apple', 'banana', 'cherry']
Enter fullscreen mode Exit fullscreen mode

โœ… 3. Sort objects with deep keys

const users = [
  { id: 1, profile: { name: "John" } },
  { id: 2, profile: { name: "Alice" } },
  { id: 3, profile: { name: "Bob" } },
];

const sortedUsers = users.mergeSortBy("profile.name");
console.log(sortedUsers.map(u => u.profile.name)); 
// ['Alice', 'Bob', 'John']
Enter fullscreen mode Exit fullscreen mode

โœ… 4. Custom comparator

const scores = [
  { name: "A", score: 90 },
  { name: "B", score: 100 },
  { name: "C", score: 95 },
];

const desc = scores.mergeSortBy((a, b) => b.score - a.score);
console.log(desc.map(x => x.score)); // [100, 95, 90]
Enter fullscreen mode Exit fullscreen mode

โฑ Performance Comparison: .sort() vs mergeSortBy()

const bigArray = Array.from({ length: 100000 }, () => ({
  id: Math.random().toString(36).substring(7),
  value: Math.floor(Math.random() * 100)
}));

console.time("Native sort");
bigArray.slice().sort((a, b) => a.value - b.value);
console.timeEnd("Native sort");

console.time("mergeSortBy");
bigArray.mergeSortBy("value");
console.timeEnd("mergeSortBy");
Enter fullscreen mode Exit fullscreen mode

โœ… Stability Test

const people = [
  { name: "Alice", age: 30 },
  { name: "Bob", age: 25 },
  { name: "Charlie", age: 30 },
];

const sorted = people.mergeSortBy("age");
console.log(sorted.map(p => p.name)); 
// ['Bob', 'Alice', 'Charlie'] โ€” Alice before Charlie (same age) โ‡’ stable!
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ Final Takeaways

You just built a custom merge sort that:

  • Handles primitives and nested objects
  • Accepts string paths or comparator functions
  • Is stable and predictable

โš ๏ธ Performance: Why Native .sort() Is Faster Than mergeSort()

After testing both Array.prototype.sort() and our custom mergeSort() on complex nested data, the results are clear:

Native Sort: โœ… Faster (~1.3ms)  
Merge Sort: โŒ Slower (~8.5ms)
Enter fullscreen mode Exit fullscreen mode

๐Ÿš€ Why is Native .sort() Faster?

Reason Description
Engine Optimized Native .sort() is implemented in low-level languages like C++ inside JS engines (e.g., V8).
Hybrid Sorting Modern engines use Timsort โ€” a hybrid of Merge and Insertion sort โ€” optimized for real-world data.
Better Memory Handling Avoids frequent array cloning operations like slice() and shift(), which are costly in JavaScript.
In-place Sorting Operates directly on the original array without creating new intermediate arrays.
Small-Array Optimization For short arrays, engines switch to insertion sort, which is extremely fast.

๐Ÿ“š Then Why Bother With mergeSort()?

While native sort is faster, writing your own mergeSort() still has value:

  • โœ… Educational: Great way to learn recursion and sorting logic.
  • ๐Ÿ” Transparent: Full control over how elements are compared and sorted.
  • ๐Ÿ”„ Immutable Structures: Useful in environments where mutation is discouraged.
  • ๐Ÿ“Š Benchmarking: Compare against other algorithms (QuickSort, HeapSort, etc.) for algorithm study.

๐Ÿง  Takeaway

Use .sort() in production.

Use mergeSort() to understand how sorting works under the hood.



๐Ÿ“ฌ What Next?

Let me know:

  • Would you like a TypeScript version?
  • Should this be a standalone NPM utility?

โญ Found this helpful? Drop a like, comment, or bookmark!


Top comments (0)