Пошук уроків, статей та іншого контенту
Розберете правила сортування та навчитеся правильно впорядковувати числа, рядки й об’єкти через sort.
sortМетод sort() упорядковує елементи масиву та повертає цей самий масив.
const fruits = ["banana", "apple", "orange"];
const sortedFruits = fruits.sort();
console.log(sortedFruits);
// ["apple", "banana", "orange"]
console.log(sortedFruits === fruits);
// truesort() змінює початковий масив. Це важливо враховувати, якщо той самий масив використовується в інших частинах програми.
Метод не приймає аргументів, якщо достатньо стандартного сортування, або приймає функцію-компаратор:
array.sort(compareFunction);Функція-компаратор отримує дві величини: a і b, а її результат визначає порядок:
від’ємне число — a має бути перед b;
додатне число — b має бути перед a;
0 — порядок між a і b можна не змінювати.
За замовчуванням sort() порівнює елементи як рядки.
const names = ["Olena", "Andrii", "Bohdan", "Anna"];
names.sort();
console.log(names);
// ["Andrii", "Anna", "Bohdan", "Olena"]Порівняння відбувається в лексикографічному порядку — приблизно так, як слова розташовані в словнику. Водночас регістр має значення:
const words = ["apple", "Banana", "cherry", "Apricot"];
words.sort();
console.log(words);
// ["Apricot", "Banana", "apple", "cherry"]Великі літери можуть розташовуватися перед малими, оскільки порівнюються відповідні Unicode-значення.
Для природнішого сортування тексту можна використовувати localeCompare():
const words = ["яблуко", "банан", "апельсин", "груша"];
words.sort((a, b) => a.localeCompare(b, "uk"));
console.log(words);
// ["апельсин", "банан", "груша", "яблуко"]Другий аргумент указує локаль, правила якої потрібно застосувати. Для українського тексту це зазвичай "uk".
Без компаратора числа сортуються як рядки:
const numbers = [10, 2, 30, 1];
numbers.sort();
console.log(numbers);
// [1, 10, 2, 30]Порівняння відбувається так:
"10" < "2"Тому для чисел потрібно явно передати функцію-компаратор:
const numbers = [10, 2, 30, 1];
numbers.sort((a, b) => a - b);
console.log(numbers);
// [1, 2, 10, 30]Вираз a - b:
повертає від’ємне число, якщо a менше за b;
повертає додатне число, якщо a більше за b;
повертає 0, якщо числа рівні.
Щоб отримати зворотний порядок, поміняйте операнди місцями:
const numbers = [10, 2, 30, 1];
numbers.sort((a, b) => b - a);
console.log(numbers);
// [30, 10, 2, 1]Той самий принцип можна записати через множення:
numbers.sort((a, b) => (a - b) * -1);Проте варіант b - a зазвичай коротший і зрозуміліший.
Розглянемо, як sort() використовує результат компаратора:
const numbers = [5, 2, 8];
numbers.sort((a, b) => {
console.log({ a, b });
return a - b;
});
console.log(numbers);
// [2, 5, 8]Метод не обов’язково порівнює сусідні елементи один раз. Конкретна кількість і порядок викликів компаратора залежать від реалізації алгоритму сортування. Тому компаратор має:
не змінювати масив;
повертати узгоджений результат;
не залежати від випадкових значень;
не виконувати зайві побічні ефекти.
Компаратор не зобов’язаний повертати саме -1, 0 або 1. Достатньо правильного знака результату:
const numbers = [4, 1, 3];
numbers.sort((a, b) => {
if (a < b) return -100;
if (a > b) return 50;
return 0;
});
console.log(numbers);
// [1, 3, 4]На практиці краще використовувати короткі вирази на кшталт a - b.
sort() змінює масив, на якому його викликали:
const original = [3, 1, 2];
const result = original.sort((a, b) => a - b);
console.log(original);
// [1, 2, 3]
console.log(result);
// [1, 2, 3]
console.log(original === result);
// trueЯкщо потрібно зберегти початковий порядок, спочатку створіть копію:
const original = [3, 1, 2];
const sorted = [...original].sort((a, b) => a - b);
console.log(original);
// [3, 1, 2]
console.log(sorted);
// [1, 2, 3]Також можна використати slice():
const sorted = original.slice().sort((a, b) => a - b);У сучасному JavaScript доступний метод toSorted(), який повертає відсортовану копію та не змінює початковий масив:
const original = [3, 1, 2];
const sorted = original.toSorted((a, b) => a - b);
console.log(original);
// [3, 1, 2]
console.log(sorted);
// [1, 2, 3]Якщо код має працювати в середовищі без підтримки toSorted(), використовуйте копію через spread або slice().
Для об’єктів стандартне сортування не дає корисного результату:
const users = [
{ name: "Olena", age: 28 },
{ name: "Andrii", age: 22 },
{ name: "Bohdan", age: 35 }
];
users.sort();
console.log(users);
// Початковий порядок може не змінитисяОб’єкти потрібно сортувати за конкретною властивістю.
const users = [
{ name: "Olena", age: 28 },
{ name: "Andrii", age: 22 },
{ name: "Bohdan", age: 35 }
];
users.sort((a, b) => a.age - b.age);
console.log(users);
// [
// { name: "Andrii", age: 22 },
// { name: "Olena", age: 28 },
// { name: "Bohdan", age: 35 }
// ]Для спадання використовуйте b.age - a.age:
users.sort((a, b) => b.age - a.age);const users = [
{ name: "Олена", age: 28 },
{ name: "Андрій", age: 22 },
{ name: "Богдан", age: 35 }
];
users.sort((a, b) => a.name.localeCompare(b.name, "uk"));
console.log(users);
// [
// { name: "Андрій", age: 22 },
// { name: "Богдан", age: 35 },
// { name: "Олена", age: 28 }
// ]Іноді потрібно сортувати за одним полем, а якщо значення однакові — за іншим.
const products = [
{ name: "Ноутбук", category: "техніка", price: 30000 },
{ name: "Мишка", category: "аксесуари", price: 800 },
{ name: "Клавіатура", category: "аксесуари", price: 1800 },
{ name: "Монітор", category: "техніка", price: 12000 }
];
products.sort((a, b) => {
const categoryOrder = a.category.localeCompare(b.category, "uk");
if (categoryOrder !== 0) {
return categoryOrder;
}
return a.price - b.price;
});
console.log(products);Алгоритм тут такий:
Спочатку порівнюються категорії.
Якщо категорії різні, використовується результат цього порівняння.
Якщо категорії однакові, порівнюються ціни.
Той самий підхід можна записати компактніше:
products.sort((a, b) =>
a.category.localeCompare(b.category, "uk") ||
a.price - b.price
);Оператор || використає ціну лише тоді, коли порівняння категорій поверне 0.
Стабільне сортування зберігає початковий порядок елементів, які вважаються рівними.
const tasks = [
{ title: "Звіт", priority: 2 },
{ title: "Лист", priority: 1 },
{ title: "Дзвінок", priority: 2 },
{ title: "План", priority: 1 }
];
tasks.sort((a, b) => a.priority - b.priority);
console.log(tasks);
// [
// { title: "Лист", priority: 1 },
// { title: "План", priority: 1 },
// { title: "Звіт", priority: 2 },
// { title: "Дзвінок", priority: 2 }
// ]У сучасному JavaScript сортування є стабільним: завдання з однаковим пріоритетом зберігають порядок "Лист" перед "План" і "Звіт" перед "Дзвінок".
Стабільність особливо корисна для послідовного сортування або коли частина об’єктів має однакові значення.
Дати краще порівнювати як об’єкти Date або за числовим timestamp:
const events = [
{ title: "Конференція", date: "2025-06-15" },
{ title: "Воркшоп", date: "2025-02-10" },
{ title: "Мітап", date: "2025-04-20" }
];
events.sort((a, b) => {
return new Date(a.date) - new Date(b.date);
});
console.log(events);
// Воркшоп, Мітап, КонференціяЯкщо дати мають формат YYYY-MM-DD, їх також можна порівнювати як рядки, оскільки цей формат розташований у хронологічному порядку:
events.sort((a, b) => a.date.localeCompare(b.date));Проте для довільних форматів дат надійніше явно перетворити значення на Date.
undefinedЕлементи зі значенням undefined переміщуються в кінець масиву, а компаратор для них може не викликатися так, як очікується. Якщо потрібно визначити власне правило, обробіть такі значення явно:
const scores = [80, undefined, 95, 60, undefined];
scores.sort((a, b) => {
if (a === undefined && b === undefined) return 0;
if (a === undefined) return 1;
if (b === undefined) return -1;
return a - b;
});
console.log(scores);
// [60, 80, 95, undefined, undefined]NaNРезультат a - b може бути NaN, якщо одне зі значень не є коректним числом. Компаратор має обробити таку ситуацію, якщо вона можлива:
const values = [10, "5", "invalid", 2];
values.sort((a, b) => {
const numberA = Number(a);
const numberB = Number(b);
const aIsInvalid = Number.isNaN(numberA);
const bIsInvalid = Number.isNaN(numberB);
if (aIsInvalid && bIsInvalid) return 0;
if (aIsInvalid) return 1;
if (bIsInvalid) return -1;
return numberA - numberB;
});
console.log(values);
// [2, "5", 10, "invalid"]Точний алгоритм сортування визначається середовищем JavaScript, тому не слід покладатися на конкретний алгоритм. Для масиву з n елементів сортування зазвичай має часову складність порядку O(n log n).
Щоб писати надійний код:
чітко визначайте тип даних, які порівнюєте;
для чисел завжди передавайте компаратор;
для тексту враховуйте регістр і локаль;
не змінюйте масив у тілі компаратора;
створюйте копію, якщо початковий масив потрібно зберегти;
обробляйте null, undefined і некоректні значення за правилами програми;
не покладайтеся на випадковий порядок, якщо компаратор повертає некоректні результати.
const values = [100, 20, 3];
values.sort();
console.log(values);
// [100, 20, 3]Правильно:
values.sort((a, b) => a - b);sort() мутує масивconst values = [3, 1, 2];
const copy = values.sort();
console.log(values);
// [1, 2, 3]Якщо потрібна копія:
const sortedValues = [...values].sort((a, b) => a - b);const values = [3, 1, 2];
values.sort((a, b) => b - a);
console.log(values);
// [3, 2, 1]b - a сортує за спаданням, а a - b — за зростанням.
Неправильно:
values.sort((a, b) => a > b);Компаратор має повертати число. Булеві значення автоматично перетворюються на 0 або 1, тому порядок може бути некоректним.
Правильно:
values.sort((a, b) => {
if (a < b) return -1;
if (a > b) return 1;
return 0;
});Або коротко:
values.sort((a, b) => a - b);localeCompare() для чисел без потребиconst values = [10, 2, 30];
values.sort((a, b) => String(a).localeCompare(String(b)));
console.log(values);
// [10, 2, 30]Це знову лексикографічне, а не числове сортування. Для чисел використовуйте арифметичний компаратор.
Нижче наведено повний приклад сортування списку замовлень:
const orders = [
{ id: 101, customer: "Олена", total: 1250, status: "paid" },
{ id: 102, customer: "Андрій", total: 800, status: "pending" },
{ id: 103, customer: "Богдан", total: 2100, status: "paid" },
{ id: 104, customer: "Анна", total: 800, status: "paid" }
];
// Створюємо копію, щоб не змінювати початковий масив.
const sortedOrders = [...orders].sort((a, b) => {
// Спочатку сортуємо за статусом.
const statusOrder = a.status.localeCompare(b.status);
if (statusOrder !== 0) {
return statusOrder;
}
// Для однакового статусу сортуємо за сумою за спаданням.
if (a.total !== b.total) {
return b.total - a.total;
}
// Якщо суми однакові, сортуємо за іменем клієнта.
return a.customer.localeCompare(b.customer, "uk");
});
console.log(sortedOrders);
console.log(orders); // Початковий порядок не змінився.Тут компаратор застосовує три рівні правил:
статус;
сума замовлення;
ім’я клієнта.
Такий підхід легко розширювати, додаючи нові критерії.
sort() сортує масив і повертає посилання на нього.
Без компаратора елементи порівнюються як рядки.
Для чисел використовуйте (a, b) => a - b.
Для сортування за спаданням використовуйте (a, b) => b - a.
Для об’єктів порівнюйте потрібні властивості.
Для українського та іншого локалізованого тексту використовуйте localeCompare().
Компаратор має повертати від’ємне число, додатне число або 0.
Якщо не можна змінювати початковий масив, спочатку створіть його копію.
Складене сортування реалізується послідовним порівнянням кількох властивостей.