Метод sort() у масиві
sort() сортує елементи масиву на місці: він змінює вихідний масив, на відміну від більшості інших методів перебору, і повертає посилання на нього ж. Метод працює і з числами, і з рядками, але коректний порядок для чисел можливий лише тоді, коли ви передасте функцію порівняння.
Теорія
TL;DR
sort()сортує на місці і повертає той самий масив, а не новий.- Без колбека елементи приводяться до рядків і порівнюються за кодами Unicode.
(a, b) => a - bдає зростання,(a, b) => b - aдає спадання.- Для рядків із урахуванням мови та регістру беріть
localeCompare. - Щоб не зіпсувати оригінал, сортуйте копію:
[...arr].sort(...). - Починаючи з ES2019 сортування стабільне: рівні елементи зберігають початковий порядок.
Швидкий приклад
const numbers = [1, 10, 2, 5];
numbers.sort();
console.log(numbers); // [1, 10, 2, 5], порівняння як рядків
numbers.sort((a, b) => a - b);
console.log(numbers); // [1, 2, 5, 10]Синтаксис і функція порівняння
array.sort(compareFunction);compareFunction це колбек такого вигляду:
(a, b) => {
// повернути від'ємне значення, якщо a має бути раніше за b
// повернути додатне значення, якщо a має бути пізніше за b
// повернути 0, якщо порядок не важливий
}За замовчуванням, без колбека, sort() сортує елементи як рядки за кодами Unicode, навіть якщо це числа. Саме тому числа без функції порівняння впорядковуються не за величиною, а посимвольно.
const fruits = ['banana', 'apple', 'cherry'];
fruits.sort();
console.log(fruits); // ['apple', 'banana', 'cherry']Сортування чисел, об'єктів і рядків
Числа за зростанням і спаданням. Функція (a, b) => a - b дає порядок за зростанням, (a, b) => b - a за спаданням.
const prices = [100, 500, 200, 50];
prices.sort((a, b) => b - a);
console.log(prices); // [500, 200, 100, 50]Сортування за властивістю об'єкта. Найчастіший сценарій на практиці, коли масив об'єктів впорядковують за числовим полем.
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 }
// ]Рядки за абеткою, без урахування регістру. localeCompare це правильний спосіб порівнювати рядки з урахуванням мови та регістру.
const names = ['tim', 'Alex', 'john'];
names.sort((a, b) => a.localeCompare(b, 'en', { sensitivity: 'base' }));
console.log(names); // ['Alex', 'john', 'tim']Сортування за кількома критеріями. Якщо вік однаковий, порядок визначає ім'я.
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 }
// ]Чому краще писати [...arr].sort()
sort() змінює вихідний масив і повертає посилання на нього, а не на новий масив.
const arr = [3, 1, 2];
const sorted = arr.sort();
console.log(sorted); // [1, 2, 3]
console.log(arr); // [1, 2, 3], це той самий масив, він змінений
console.log(arr === sorted); // trueЦе небезпечно, коли масив приходить із пропсів, зі стану застосунку чи з кешу: сортування «для показу» непомітно перебудовує дані, на які покладається інший код, а React чи Vue можуть не помітити зміни, бо посилання лишилося тим самим. Тому перед сортуванням роблять копію.
const sortedCopy = [...arr].sort((a, b) => a - b);Копія коштує один прохід по масиву, а натомість ви отримуєте чисту функцію без побічних ефектів. У сучасних середовищах ту саму ідею виражає вбудований метод toSorted(), який одразу повертає новий масив і не чіпає оригінал.
Коли брати sort(), а коли інші методи
| Мета | Чи підходить sort() |
|---|---|
| Відсортувати числа або рядки | Так |
| Відсортувати об'єкти за полем | Так |
| Отримати новий відсортований масив без зміни оригіналу | Так, але лише через копію [...arr] |
| Перевірити умову | Ні |
| Трансформувати дані | Ні |
Порівняння з сусідніми методами:
| Метод | Повертає новий масив | Змінює вихідний | Призначення |
|---|---|---|---|
map() | так | ні | перетворює елементи |
filter() | так | ні | відбирає елементи |
find() | ні, повертає елемент | ні | знаходить перший елемент |
reduce() | ні, повертає одне значення | ні | зводить до одного результату |
sort() | ні, повертає той самий масив | так | сортує елементи |
Формула для запам'ятовування: arr.sort((a, b) => a - b) це зростання, arr.sort((a, b) => b - a) це спадання.
Типові помилки
1. Сортувати числа без колбека. Елементи порівнюються як рядки, тож 10 опиняється перед 2.
[10, 2, 1].sort(); // [1, 10, 2], порівняння як рядківПравильно:
[10, 2, 1].sort((a, b) => a - b); // [1, 2, 10]2. Не помітити мутацію вихідного масиву.
const a = [3, 1, 2];
const b = a.sort();
console.log(a === b); // true, це той самий об'єкт3. Розраховувати на стабільність у старих рушіях. До ES2019 сортування могло бути нестабільним, і елементи з однаковим ключем могли міняти взаємний порядок. У сучасних версіях ECMAScript sort() стабільний.
4. Повертати з колбека булеве значення. (a, b) => a > b повертає true або false, а не від'ємне число, нуль чи додатне, тому порядок виходить непередбачуваним. Завжди повертайте число.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.