Sorting Arrays
Sorting looks simple but has two famous traps in JavaScript: by default, sort compares items as strings, and it changes the original array. Once you know how compare functions work, you can sort numbers, dates, objects by any property, and text in any language.
The default sort
const names = ["Mia", "ada", "Zoe", "Ben"]; names.sort(); console.log(names); const numbers = [100, 25, 3, 1000]; numbers.sort(); console.log(numbers);
[ 'Ben', 'Mia', 'Zoe', 'ada' ] [ 100, 1000, 25, 3 ]
Without arguments, sort converts every item to a string and orders by Unicode code points. That puts uppercase before lowercase and sorts numbers "alphabetically": "1000" comes before "25" because "1" comes before "2".
Compare functions
Pass a function that takes two items, a and b, and returns:
- a negative number if
ashould come first, - a positive number if
bshould come first, - 0 if their order doesn't matter.
const numbers = [100, 25, 3, 1000];
console.log([...numbers].sort((a, b) => a - b));
console.log([...numbers].sort((a, b) => b - a));
[ 3, 25, 100, 1000 ] [ 1000, 100, 25, 3 ]
a - b is negative when a is smaller, so smaller numbers go first (ascending). b - a reverses it.
sort changes the original
const original = [3, 1, 2]; const sorted = original.sort((a, b) => a - b); console.log(original); console.log(sorted === original); const safe = [3, 1, 2]; const copy = safe.toSorted((a, b) => a - b); console.log(safe, copy);
[ 1, 2, 3 ] true [ 3, 1, 2 ] [ 1, 2, 3 ]
sort sorts in place and returns the same array. To keep the original, use toSorted or copy first with [...arr].sort(…).
Sorting objects by a property
const products = [ { name: "Desk", price: 120, rating: 4.1 }, { name: "Lamp", price: 30, rating: 4.8 }, { name: "Chair", price: 75, rating: 4.8 }, ]; const cheapest = products.toSorted((a, b) => a.price - b.price); console.log(cheapest.map(p => p.name)); const best = products.toSorted((a, b) => b.rating - a.rating || a.price - b.price); console.log(best.map(p => p.name));
[ 'Lamp', 'Chair', 'Desk' ] [ 'Lamp', 'Chair', 'Desk' ]
The second sort orders by rating (highest first), and breaks ties by price: when ratings are equal, b.rating - a.rating is 0 (falsy), so || falls through to the price comparison.
Sorting text properly
localeCompare compares strings the way a human would expect, ignoring case differences and handling accents:
const words = ["zebra", "Apple", "éclair", "banana"]; console.log(words.toSorted()); console.log(words.toSorted((a, b) => a.localeCompare(b))); const files = ["file10", "file2", "file1"]; console.log(files.toSorted((a, b) => a.localeCompare(b, undefined, { numeric: true })));
[ 'Apple', 'banana', 'zebra', 'éclair' ] [ 'Apple', 'banana', 'éclair', 'zebra' ] [ 'file1', 'file2', 'file10' ]
The numeric: true option gives "natural" ordering for strings that contain numbers. For sorting large lists, creating one Intl.Collator and reusing its compare method is faster.
Sorting dates
const events = [ { title: "Launch", date: new Date("2026-11-01") }, { title: "Kickoff", date: new Date("2026-03-15") }, { title: "Review", date: new Date("2026-07-20") }, ]; events.sort((a, b) => a.date - b.date); console.log(events.map(e => e.title));
[ 'Kickoff', 'Review', 'Launch' ]
Subtracting two dates gives the difference in milliseconds, which works directly as a compare result. ISO date strings ("2026-03-15") can also be compared with localeCompare, because their text order matches date order.
Reverse and shuffle
const deck = [1, 2, 3, 4, 5]; function shuffle(array) { const result = [...array]; for (let i = result.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [result[i], result[j]] = [result[j], result[i]]; } return result; } const shuffled = shuffle(deck); console.log(shuffled.length, shuffled.toSorted((a, b) => a - b).join() === deck.join());
5 true
This is the Fisher–Yates shuffle, which gives every order an equal chance. The tempting shortcut sort(() => Math.random() - 0.5) is biased and shouldn't be used.