Array.prototype.toSorted()
Returns a sorted copy of an array, leaving the original in its existing order.
toSorted()
toSorted(compareFn)- Added in JavaScript ECMAScript 2023
Parameters
| Parameter | Type | Description |
|---|---|---|
$compareFnoptional | (a: any, b: any) => number= undefined | Determines order. Return a negative number to put a first, a positive number to put b first, 0 to keep them adjacent. Omitted, elements are compared as strings by UTF-16 code unit. |
Return value
ArrayA new array with the elements sorted in ascending order; the original array is unchanged.
Errors
Throws a TypeError if compareFn is provided but is not a function, or if called on null or undefined.
Changelog
- PHP ECMAScript 2019The underlying sort is required to be stable, so equal elements keep their original relative order in engines that follow the current spec.
toSorted() does what [...arr].sort() does, in one call: it copies the array and sorts the copy. The receiver keeps its original order, which removes the classic bug where sorting a list for display silently reorders the data everyone else is reading.
When to reach for it
Any time the array is not yours to reorder — component props, module-level constants, values in a store, or an array you are iterating elsewhere. It also composes: rows.toSorted(byDate).at(-1) reads the newest row without naming an intermediate.
What trips people up
- The default comparison is lexicographic. Without a
compareFn, elements are converted to strings, so[10, 1, 2].toSorted()is[1, 10, 2]. Pass(a, b) => a - bfor numbers. undefinedvalues are always sorted to the end and never passed tocompareFn; empty slots are treated the same way.- The copy is shallow, so sorting objects reorders references — mutating one still affects the source array's element.
- Your comparator must be consistent. Returning
a > b(a boolean) or a random number gives implementation-defined results.
Use Intl.Collator for human-readable text ordering; the default string comparison sorts by code unit, so "Z" comes before "a".
Example
When to use it
- Display a sorted view of a list without reordering the source data.
- Sort component props or store state that must stay immutable.
- Rank records by score and read the top one in a single chained expression.
- Compare a sorted copy against the original to detect whether a list is already ordered.
Frequently asked questions
How do I sort an array without changing the original?
Call arr.toSorted(compareFn) — it copies first, then sorts the copy. It is equivalent to [...arr].sort(compareFn) but does not need the spread and works on frozen arrays.
Why does toSorted() put 10 before 9?
Because without a comparator elements are compared as strings, and "10" is less than "9". Pass (a, b) => a - b to sort numerically.
Is toSorted() stable?
Yes, the specification requires a stable sort, so elements your comparator reports as equal keep their original relative order. That lets you sort by a secondary key first and a primary key second.
More examples
Sorting objects by a field
Bo and Cy tie on age and keep their original relative order because the sort is stable. The copy holds the very same objects, as the identity check on the last line shows.
const people = [
{ name: "Bo", age: 30 },
{ name: "Al", age: 25 },
{ name: "Cy", age: 30 },
];
const byAge = people.toSorted((a, b) => a.age - b.age);
console.log(byAge.map((p) => p.name));
console.log(people.map((p) => p.name));
console.log(byAge[1] === people[0]);toSorted() vs sort()
sort() returns the same array it reordered, so mutated === source is true and the original is gone. toSorted() returns a new array and therefore also works on a frozen one, which sort() cannot.
const source = [3, 1, 2];
const copy = source.toSorted((a, b) => a - b);
console.log(copy, source);
const mutated = source.sort((a, b) => a - b);
console.log(mutated === source, source);
console.log(Object.freeze([3, 1, 2]).toSorted((a, b) => a - b));Human-readable text order
The default sort compares UTF-16 code units, so uppercase and accented letters land in the wrong places. Intl.Collator.compare produces the ordering a reader expects.
const words = ["apple", "Banana", "cherry", "Ärger"];
console.log(words.toSorted());
const collator = new Intl.Collator("en", { sensitivity: "base" });
console.log(words.toSorted(collator.compare));
Discussion