Сортировка массива объектов по значениям свойств в JavaScript
Как работает сортировка массива объектов
Метод Array.prototype.sort() в JavaScript по умолчанию преобразует элементы в строки и сортирует их в лексикографическом порядке. Для сортировки объектов нужно передать функцию сравнения, которая возвращает:
- Отрицательное число — если первый элемент должен идти раньше второго
- Ноль — если элементы равны
- Положительное число — если первый элемент должен идти после второго
Простая сортировка по одному полю
Для сортировки по возрасту (числовое поле) используем вычитание:
const users = [
{ name: 'Анна', age: 25 },
{ name: 'Иван', age: 30 },
{ name: 'Мария', age: 22 },
{ name: 'Петр', age: 28 }
];
// По возрастанию возраста
users.sort((a, b) => a.age - b.age);
console.log(users);
// Результат: Мария(22), Анна(25), Петр(28), Иван(30)
// По убыванию возраста
users.sort((a, b) => b.age - a.age);
console.log(users);
// Результат: Иван(30), Петр(28), Анна(25), Мария(22)
Почему это работает? Если a.age = 25, а b.age = 30, то a.age - b.age = -5 — отрицательное число, значит a (Анна) будет перед b (Иван).
Сортировка по строковому полю
Для строк используем методы localeCompare() или toString().localeCompare():
// По имени (алфавитный порядок)
users.sort((a, b) => a.name.localeCompare(b.name));
console.log(users);
// Результат: Анна, Иван, Мария, Петр
// По имени (обратный алфавитный порядок)
users.sort((a, b) => b.name.localeCompare(a.name));
localeCompare() возвращает -1, 0 или 1, что идеально подходит для сортировки. Он также корректно обрабатывает русские буквы и спецсимволы.
Сортировка по нескольким полям
Для сортировки сначала по возрасту, а затем по имени (при одинаковом возрасте) используем цепочку сравнений:
const usersWithDuplicates = [
{ name: 'Анна', age: 25 },
{ name: 'Иван', age: 30 },
{ name: 'Мария', age: 25 }, // одинаковый возраст с Анной
{ name: 'Петр', age: 28 },
{ name: 'Алексей', age: 25 } // одинаковый возраст с Анной и Марией
];
usersWithDuplicates.sort((a, b) => {
// Сначала сравниваем по возрасту
if (a.age !== b.age) {
return a.age - b.age;
}
// Если возраст одинаковый — сравниваем по имени
return a.name.localeCompare(b.name);
});
console.log(usersWithDuplicates);
// Результат:
// 1. Алексей (25) — по алфавиту среди 25-летних
// 2. Анна (25)
// 3. Мария (25)
// 4. Петр (28)
// 5. Иван (30)
Можно записать компактнее через логические операторы:
usersWithDuplicates.sort((a, b) =>
a.age - b.age || a.name.localeCompare(b.name)
);
Здесь || работает так: если a.age - b.age не равно 0 (то есть возраста разные), то возвращается это значение. Если равно 0 (возраста одинаковые), то выполняется вторая часть — сравнение по имени.
Важные замечания
- Мутация исходного массива:
sort()изменяет массив на месте. Если нужно сохранить оригинал, создайте копию:const sorted = [...users].sort(...) - Стабильность сортировки: Современные браузеры (ES2019+) используют стабильную сортировку — элементы с одинаковыми значениями сохраняют исходный порядок. Для старых браузеров это не гарантируется.
- Сортировка по вложенным свойствам: Если объект имеет структуру
{user: {name: 'Анна', age: 25}}, используйтеa.user.age - b.user.age - Сортировка по датам: Преобразуйте даты в числа (timestamp):
new Date(a.date) - new Date(b.date)
Продвинутый пример: динамическая сортировка
function sortByFields(arr, fields) {
return [...arr].sort((a, b) => {
for (const { field, order = 'asc' } of fields) {
const aVal = a[field];
const bVal = b[field];
if (aVal === bVal) continue;
const compare = typeof aVal === 'string'
? aVal.localeCompare(bVal)
: aVal - bVal;
return order === 'desc' ? -compare : compare;
}
return 0;
});
}
// Использование:
const sorted = sortByFields(users, [
{ field: 'age', order: 'asc' },
{ field: 'name', order: 'asc' }
]);
<<Альтернативный подход: использование библиотеки Lodash
Если вы часто работаете со сложными сортировками и не хотите писать функции сравнения вручную, можно использовать утилиту _.sortBy() из популярной библиотеки Lodash:
// Установка: npm install lodash
// Или подключение через CDN:
Похожие вопросы
Python when should I use ASYNC, and when is AWAIT?
SwiftUI: Как реализовать кастомный init с @Binding переменными
Ошибка "undefined reference/unresolved external symbol" в C++: причины и исправление
Как установить, сбросить и переключить отдельный бит в C++?
Как получить текущий год в PHP: простые способы и примеры