Skip to main content

Array sort() method

sort() sorts array elements in place: it modifies the source array, unlike most other iteration methods, and returns a reference to that same array. It works with both numbers and strings, but a correct numeric order is only possible when you pass a comparison function.

Theory

TL;DR

  • sort() sorts in place and returns the same array, not a new one.
  • Without a callback the elements are coerced to strings and compared by Unicode code points.
  • (a, b) => a - b gives ascending order, (a, b) => b - a gives descending order.
  • For strings that must respect language and case, use localeCompare.
  • To keep the original intact, sort a copy: [...arr].sort(...).
  • Since ES2019 the sort is stable: equal elements keep their original order.

Quick example

javascript
const numbers = [1, 10, 2, 5]; numbers.sort(); console.log(numbers); // [1, 10, 2, 5], compared as strings numbers.sort((a, b) => a - b); console.log(numbers); // [1, 2, 5, 10]

Syntax and the comparison function

javascript
array.sort(compareFunction);

compareFunction is a callback of this shape:

javascript
(a, b) => { // return a negative value if a should come before b // return a positive value if a should come after b // return 0 if the order does not matter }

By default, with no callback, sort() orders elements as strings by Unicode code points, even when they are numbers. That is why numbers without a comparison function end up ordered character by character rather than by value.

javascript
const fruits = ['banana', 'apple', 'cherry']; fruits.sort(); console.log(fruits); // ['apple', 'banana', 'cherry']

Sorting numbers, objects and strings

Numbers ascending and descending. The function (a, b) => a - b gives ascending order, (a, b) => b - a gives descending order.

javascript
const prices = [100, 500, 200, 50]; prices.sort((a, b) => b - a); console.log(prices); // [500, 200, 100, 50]

Sorting by an object property. The most common scenario in practice, when an array of objects is ordered by a numeric field.

javascript
const users = [ { name: 'Tim', age: 25 }, { name: 'Alex', age: 30 }, { name: 'John', age: 20 } ]; users.sort((a, b) => a.age - b.age); console.log(users); // [ // { name: 'John', age: 20 }, // { name: 'Tim', age: 25 }, // { name: 'Alex', age: 30 } // ]

Strings alphabetically, ignoring case. localeCompare is the correct way to compare strings while respecting language and case.

javascript
const names = ['tim', 'Alex', 'john']; names.sort((a, b) => a.localeCompare(b, 'en', { sensitivity: 'base' })); console.log(names); // ['Alex', 'john', 'tim']

Sorting by several criteria. When the age is the same, the name decides the order.

javascript
const users = [ { name: 'Tim', age: 25 }, { name: 'Alex', age: 25 }, { name: 'John', age: 20 } ]; users.sort((a, b) => { if (a.age !== b.age) return a.age - b.age; return a.name.localeCompare(b.name); }); console.log(users); // [ // { name: 'John', age: 20 }, // { name: 'Alex', age: 25 }, // { name: 'Tim', age: 25 } // ]

Why [...arr].sort() is the better habit

sort() modifies the source array and returns a reference to it, not to a new array.

javascript
const arr = [3, 1, 2]; const sorted = arr.sort(); console.log(sorted); // [1, 2, 3] console.log(arr); // [1, 2, 3], the very same array, mutated console.log(arr === sorted); // true

That is dangerous when the array comes from props, from application state or from a cache: sorting it "just for display" quietly rebuilds data other code relies on, and React or Vue may miss the change because the reference stayed the same. So you copy before sorting.

javascript
const sortedCopy = [...arr].sort((a, b) => a - b);

The copy costs one pass over the array, and in exchange you get a pure operation with no side effects. In modern environments the built in toSorted() method expresses the same idea: it returns a new array and leaves the original alone.

When to use sort() and when to use other methods

GoalIs sort() a good fit
Sort numbers or stringsYes
Sort objects by a fieldYes
Get a new sorted array without touching the originalYes, but only through a copy [...arr]
Check a conditionNo
Transform dataNo

A comparison with the neighbouring methods:

MethodReturns a new arrayMutates the sourcePurpose
map()yesnotransforms elements
filter()yesnoselects elements
find()no, returns an elementnofinds the first element
reduce()no, returns one valuenofolds into a single result
sort()no, returns the same arrayyessorts elements

A formula worth memorising: arr.sort((a, b) => a - b) is ascending, arr.sort((a, b) => b - a) is descending.

Common mistakes

1. Sorting numbers without a callback. Elements are compared as strings, so 10 ends up before 2.

javascript
[10, 2, 1].sort(); // [1, 10, 2], compared as strings

The fix:

javascript
[10, 2, 1].sort((a, b) => a - b); // [1, 2, 10]

2. Not noticing that the source array is mutated.

javascript
const a = [3, 1, 2]; const b = a.sort(); console.log(a === b); // true, it is the same object

3. Relying on stability in old engines. Before ES2019 the sort could be unstable, and elements with an equal key could swap their relative order. In modern ECMAScript versions sort() is stable.

4. Returning a boolean from the callback. (a, b) => a > b returns true or false rather than a negative number, zero or a positive number, so the resulting order is unpredictable. Always return a number.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.