Avatar ·

Сортировка массива объектов по значениям свойств в JavaScript

Всем привет! Я новичок в JavaScript и столкнулся с проблемой при сортировке массива объектов. У меня есть массив пользователей, каждый объект содержит имя и возраст: ```javascript const users = [ { name: 'Анна', age: 25 }, { name: 'Иван', age: 30 }, { name: 'Мария', age: 22 }, { name: 'Петр', age: 28 } ]; ``` Мне нужно отсортировать этот массив по возрасту (от младшего к старшему), а потом по имени в алфавитном порядке. Я пробовал использовать метод `sort()` напрямую, но он не работает как ожидалось — сортирует как строки, и объекты не сравниваются правильно. Я читал, что `sort()` принимает функцию сравнения, но не могу понять, как её написать для объектов. Пробовал что-то вроде `users.sort((a, b) => a.age - b.age)`, но результат странный — иногда сортирует, иногда нет. Ещё я хочу сортировать сначала по возрасту, а если возраст одинаковый — по имени. Как это правильно сделать? Подскажите, пожалуйста, как работает сортировка объектов в 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: