JavaScript Array Sort Method: Complete Guide

sort() arranges array elements in place. Learn how default string sorting works, how to write a compare function for numbers and objects, and common pitfalls.

6 min read

sort() arranges the elements of an array in place and returns the sorted array. It seems simple but has a default behavior that surprises nearly every JavaScript beginner: it sorts everything as strings, regardless of whether the values are actually numbers.

javascriptjavascript
const numbers = [3, 1, 10, 2, 20];
 
numbers.sort();
 
console.log(numbers); // [1, 10, 2, 20, 3] -- not what you expected!

The default sort() converts each element to a string and compares them character by character. The string "10" comes before "2" because "1" is less than "2". This is called lexicographic order.

To sort numbers correctly, you must provide a compare function that tells sort() how to compare two values numerically instead of as text.

The Compare Function

A compare function takes two elements (a and b) and returns a number that tells sort() how to order them:

Return valueMeaning
Negative (< 0)Place a before b
Zero (0)Keep the order of a and b unchanged
Positive (> 0)Place b before a

The simplest numeric compare function subtracts one from the other:

javascriptjavascript
const numbers = [3, 1, 10, 2, 20];
 
// Ascending order (small to large)
numbers.sort((a, b) => a - b);
 
console.log(numbers); // [1, 2, 3, 10, 20]

For descending order, swap the subtraction so larger numbers produce a negative result and sort to the front instead of the back:

javascriptjavascript
numbers.sort((a, b) => b - a);
 
console.log(numbers); // [20, 10, 3, 2, 1]
Compare function determines sort order

The compare function is called multiple times during sorting. You do not need to worry about the sorting algorithm -- the engine handles that. You just define the order rule, and the engine applies it consistently across every pair of elements it needs to compare.

Sorting Strings

For strings, the default sort() works for basic alphabetical order:

javascriptjavascript
const fruits = ["banana", "apple", "cherry", "date"];
 
fruits.sort();
 
console.log(fruits); // ["apple", "banana", "cherry", "date"]

But default sort is case-sensitive. Uppercase letters come before lowercase in string comparison, which can put capitalized words in unexpected positions:

javascriptjavascript
const mixed = ["Banana", "apple", "Cherry", "date"];
 
mixed.sort();
 
console.log(mixed); // ["Banana", "Cherry", "apple", "date"]

For case-insensitive sorting, use localeCompare() with a sensitivity option that treats uppercase and lowercase letters as equal instead of comparing raw character codes:

javascriptjavascript
mixed.sort((a, b) => a.localeCompare(b, undefined, { sensitivity: "base" }));
 
console.log(mixed); // ["apple", "Banana", "Cherry", "date"]

localeCompare() handles language-specific sorting rules, such as accented characters and locale-specific alphabetical order, and is the right choice for user-facing string sorting.

Sorting Objects by a Property

To sort an array of objects, access the property inside the compare function instead of comparing the objects directly:

javascriptjavascript
const products = [
  { name: "Laptop", price: 999 },
  { name: "Mouse", price: 29 },
  { name: "Monitor", price: 299 },
  { name: "Keyboard", price: 79 }
];
 
products.sort((a, b) => a.price - b.price);

Sorting by price puts the cheapest product first and the most expensive last, matching the ascending order the subtraction produces:

javascriptjavascript
console.log(products.map(p => p.name));
// ["Mouse", "Keyboard", "Monitor", "Laptop"]

The same pattern works for string properties, using localeCompare() instead of subtraction since strings cannot be subtracted the way numbers can:

javascriptjavascript
const users = [
  { name: "Carol", age: 30 },
  { name: "Alice", age: 25 },
  { name: "Bob", age: 35 }
];
 
users.sort((a, b) => a.name.localeCompare(b.name));
 
console.log(users);
// Alice, Bob, Carol

Sorting by Multiple Criteria

Chain comparisons to sort by a secondary field when the primary field is equal. Compare the primary field first, and only fall back to the secondary field when that comparison is a tie:

javascriptjavascript
const students = [
  { name: "Alice", grade: "B" },
  { name: "Bob", grade: "A" },
  { name: "Carol", grade: "B" },
  { name: "Dave", grade: "A" }
];

The compare function returns the grade comparison immediately when it is non-zero, and only reaches the name comparison when both students share a grade:

javascriptjavascript
students.sort((a, b) => {
  const gradeCompare = a.grade.localeCompare(b.grade);
  if (gradeCompare !== 0) return gradeCompare;
  return a.name.localeCompare(b.name);
});

Students with the same grade end up sorted alphabetically by name within that grade group, since the secondary comparison only runs when grades tie:

javascriptjavascript
console.log(students.map(s => `${s.name} (${s.grade})`));
// ["Bob (A)", "Dave (A)", "Alice (B)", "Carol (B)"]

sort() Mutates the Original Array

sort() sorts the array in place and returns a reference to that same array, not a new one, which surprises developers used to methods like map():

javascriptjavascript
const original = [3, 1, 2];
 
const sorted = original.sort((a, b) => a - b);
 
console.log(original); // [1, 2, 3] (mutated!)
console.log(sorted);   // [1, 2, 3] (same array)
console.log(original === sorted); // true

To sort without mutating, create a copy first with the spread operator, then sort the copy instead of the original:

javascriptjavascript
const original = [3, 1, 2];
 
const sorted = [...original].sort((a, b) => a - b);
 
console.log(original); // [3, 1, 2] (unchanged)
console.log(sorted);   // [1, 2, 3]

This copy-then-sort pattern is worth using by default in any function that receives an array it does not own, since callers rarely expect their data to change. For more on copying arrays, see JS Spread Operator for Arrays.

Sorting Dates

Dates sort correctly with a numeric compare function because JavaScript dates convert to milliseconds when subtracted:

javascriptjavascript
const events = [
  { name: "Conference", date: new Date("2026-08-15") },
  { name: "Workshop", date: new Date("2026-06-01") },
  { name: "Meetup", date: new Date("2026-09-20") }
];
 
events.sort((a, b) => a.date - b.date);
 
console.log(events);
// Workshop (June), Conference (August), Meetup (September)

Common Mistakes

Using sort() on numbers without a compare function. This silently produces string-order results instead of numeric order, and nothing warns you that it happened:

javascriptjavascript
// Wrong: default string sort
[100, 5, 20, 1].sort(); // [1, 100, 20, 5]
 
// Right: numeric compare function
[100, 5, 20, 1].sort((a, b) => a - b); // [1, 5, 20, 100]

This is the single most common array mistake in JavaScript. Never sort numbers without a compare function, even when the array looks small enough that the bug seems unlikely to matter.

Forgetting that sort() mutates. A function that sorts an argument array silently changes the caller's original data too, which can cause confusing bugs elsewhere:

javascriptjavascript
const data = [3, 1, 2];
 
function processData(arr) {
  arr.sort((a, b) => a - b); // Mutates the caller's array!
  return arr;
}
 
const sorted = processData(data);
console.log(data); // [1, 2, 3] -- original changed!

Functions that sort their arguments should either copy first or clearly document that they mutate their input. When in doubt, prefer copying: [...arr].sort(...).

Trying to sort() on an array with mixed types. Without a compare function, everything still gets converted to a string first, even numbers mixed in with text:

javascriptjavascript
const mixed = [1, "hello", 3, "world"];
 
// sort() works but the result is based on string conversion
mixed.sort();
console.log(mixed); // [1, 3, "hello", "world"] (numbers first, then strings)

JavaScript's sort() has been required to be stable since ES2019, meaning equal elements always keep their original relative order. But mixed-type arrays still produce results that are rarely useful. Keep arrays homogeneous when sorting.

Now that you can sort arrays, learn how to remove duplicates from sorted data.

Rune AI

Rune AI

Key Insights

  • sort() converts elements to strings by default, so [3, 1, 10] sorts to [1, 10, 3].
  • Always provide a compare function for numeric sorting: (a, b) => a - b.
  • sort() mutates the original array. Copy first with [...arr] to avoid mutation.
  • Return a negative number to place a before b, positive to place b before a, 0 to keep equal.
  • For objects, access the property in the compare function: (a, b) => a.price - b.price.
RunePowered by Rune AI

Frequently Asked Questions

Why does sort() put 10 before 2?

By default, sort() converts elements to strings and compares them lexicographically. The string '10' comes before '2' because '1' is less than '2'. To sort numerically, always provide a compare function: arr.sort((a, b) => a - b).

Does sort() change the original array?

Yes. sort() mutates the original array in place and also returns a reference to it. To sort without mutating, make a copy first: [...arr].sort().

How do I sort an array of objects by a property?

Use a compare function that accesses the property: arr.sort((a, b) => a.age - b.age) for numeric properties, or arr.sort((a, b) => a.name.localeCompare(b.name)) for string properties.

Conclusion

sort() is powerful but has a surprising default behavior that catches every beginner at least once. The key rule: never use sort() without a compare function for numbers, and always remember it mutates the original array. Once you master the compare function pattern, you can sort anything -- numbers, strings, dates, and complex objects by any property.