Skip to main content

Метод sort() у масиві

sort() сортує елементи масиву на місці: він змінює вихідний масив, на відміну від більшості інших методів перебору, і повертає посилання на нього ж. Метод працює і з числами, і з рядками, але коректний порядок для чисел можливий лише тоді, коли ви передасте функцію порівняння.

Теорія

TL;DR

  • sort() сортує на місці і повертає той самий масив, а не новий.
  • Без колбека елементи приводяться до рядків і порівнюються за кодами Unicode.
  • (a, b) => a - b дає зростання, (a, b) => b - a дає спадання.
  • Для рядків із урахуванням мови та регістру беріть localeCompare.
  • Щоб не зіпсувати оригінал, сортуйте копію: [...arr].sort(...).
  • Починаючи з ES2019 сортування стабільне: рівні елементи зберігають початковий порядок.

Швидкий приклад

javascript
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]

Синтаксис і функція порівняння

javascript
array.sort(compareFunction);

compareFunction це колбек такого вигляду:

javascript
(a, b) => { // повернути від'ємне значення, якщо a має бути раніше за b // повернути додатне значення, якщо a має бути пізніше за b // повернути 0, якщо порядок не важливий }

За замовчуванням, без колбека, sort() сортує елементи як рядки за кодами Unicode, навіть якщо це числа. Саме тому числа без функції порівняння впорядковуються не за величиною, а посимвольно.

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

Сортування чисел, об'єктів і рядків

Числа за зростанням і спаданням. Функція (a, b) => a - b дає порядок за зростанням, (a, b) => b - a за спаданням.

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

Сортування за властивістю об'єкта. Найчастіший сценарій на практиці, коли масив об'єктів впорядковують за числовим полем.

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 } // ]

Рядки за абеткою, без урахування регістру. localeCompare це правильний спосіб порівнювати рядки з урахуванням мови та регістру.

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

Сортування за кількома критеріями. Якщо вік однаковий, порядок визначає ім'я.

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 } // ]

Чому краще писати [...arr].sort()

sort() змінює вихідний масив і повертає посилання на нього, а не на новий масив.

javascript
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 можуть не помітити зміни, бо посилання лишилося тим самим. Тому перед сортуванням роблять копію.

javascript
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.

javascript
[10, 2, 1].sort(); // [1, 10, 2], порівняння як рядків

Правильно:

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

2. Не помітити мутацію вихідного масиву.

javascript
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, а не від'ємне число, нуль чи додатне, тому порядок виходить непередбачуваним. Завжди повертайте число.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.