Статьи

Совет: как отсортировать массив объектов в JavaScript

Если у вас есть массив объектов, которые вам нужно отсортировать в определенном порядке, у вас может возникнуть желание найти библиотеку JavaScript. Но прежде чем вы это сделаете, помните, что вы можете сделать довольно аккуратную сортировку с помощью встроенной функции Array.sort .

В этой статье мы покажем вам, как сортировать массив объектов в JavaScript без суеты и беспокойства.

Для продолжения вам понадобится знание основных концепций JavaScript, таких как объявление переменных, функций записи и условных операторов. Мы также будем использовать синтаксис ES6. Вы можете получить дополнительную информацию об этом через нашу обширную коллекцию руководств ES6 . Эта популярная статья была обновлена ​​в ноябре 2019 года.

Сортировать массив объектов в JavaScript

Основная сортировка массива

По умолчанию функция JavaScript Array.sortкодов Unicode .

 const foo = [9, 1, 4, 'zebroid', 'afterdeck'];
foo.sort(); // returns [ 1, 4, 9, 'afterdeck', 'zebroid' ]

const bar = [5, 18, 32, new Set, { user: 'Eleanor Roosevelt' }];
bar.sort(); // returns [ 18, 32, 5, { user: 'Eleanor Roosevelt' }, Set {} ]

Вы можете быть удивлены, почему 32 предшествует 5. Не логично, а? Ну, на самом деле это так. Это происходит потому, что каждый элемент в массиве сначала преобразуется в строку, а "32""5"

Стоит также отметить, что в отличие от многих других функций массива JavaScript, Array.sort

 const baz = ['My cat ate my homework', 37, 9, 5, 17];
baz.sort(); // baz array is modified
console.log(baz); // shows [ 17, 37, 5, 9, 'My cat ate my homework' ]

Чтобы избежать этого, вы можете создать новый экземпляр массива для сортировки и изменить его. Это возможно с помощью метода массива, который возвращает копию массива. Например, Array.slice :

 const sortedBaz = baz.slice().sort(); // a new instance of the baz array is created and sorted

Или, если вы предпочитаете более новый синтаксис, вы можете использовать оператор распространения для того же эффекта:

 const sortedBaz = [...baz].sort(); // a new instance of the baz array is created and sorted

Вывод одинаков в обоих случаях:

 console.log(baz); // ['My cat ate my homework', 37, 9, 5, 17];
console.log(sortedBaz); // [ 17, 37, 5, 9, 'My cat ate my homework' ]

Попробуйте это

Использование Array.sort К счастью, функция принимает необязательный параметр compareFunction

Использование функций сравнения для сортировки

Допустим, что foobar

  1. меньше 0 — foobar
  2. больше 0 — barfoo
  3. равно 0 — foobar

Давайте рассмотрим простой пример с массивом чисел:

 const nums = [79, 48, 12, 4];

function compare(a, b) {
  if (a > b) return 1;
  if (b > a) return -1;

  return 0;
}

nums.sort(compare);
// => 4, 12, 48, 79

Мы можем немного изменить рефакторинг, так как вычитание ab

 function compare(a, b) {
  return a - b;
}

Теперь это хороший кандидат на функцию стрелки:

 nums.sort((a, b) => a - b);

Если вы не знакомы с функциями стрелок, вы можете прочитать о них здесь: Функции стрелок ES6: толстый и краткий синтаксис в JavaScript .

Как отсортировать массив объектов в JavaScript

Теперь давайте посмотрим на сортировку массива объектов. Для этой демонстрации мы будем использовать массив певцов:

 const singers = [
  { name: 'Steven Tyler', band: 'Aerosmith', born: 1948 },
  { name: 'Karen Carpenter', band: 'The Carpenters', born: 1950 },
  { name: 'Kurt Cobain', band: 'Nirvana', born: 1967 },
  { name: 'Stevie Nicks', band: 'Fleetwood Mac', born: 1948 },
];

Мы можем использовать следующую функцию compare

 function compare(a, b) {
  // Use toUpperCase() to ignore character casing
  const bandA = a.band.toUpperCase();
  const bandB = b.band.toUpperCase();

  let comparison = 0;
  if (bandA > bandB) {
    comparison = 1;
  } else if (bandA < bandB) {
    comparison = -1;
  }
  return comparison;
}

singers.sort(compare);

/* returns [
  { name: 'Steven Tyler', band: 'Aerosmith',  born: 1948 },
  { name: 'Stevie Nicks', band: 'Fleetwood Mac', born: 1948 },
  { name: 'Kurt Cobain', band: 'Nirvana', born: 1967 },
  { name: 'Karen Carpenter', band: 'The Carpenters', born: 1950 }
] */

Чтобы изменить порядок сортировки, вы можете инвертировать возвращаемое значение функции compare

 function compare(a, b) {
  ...

  //invert return value by multiplying by -1
  return comparison * -1;
}

Попробуйте это

Создание функции динамической сортировки

Давайте закончим, сделав это более динамичным. Давайте создадим функцию сортировки, которую вы можете использовать для сортировки массива объектов, значениями которых являются либо строки, либо числа. Эта функция имеет два параметра — ключ, по которому мы хотим отсортировать, и порядок результатов (т. Е. Возрастания или убывания):

 const singers = [
  { name: 'Steven Tyler', band: 'Aerosmith', born: 1948 },
  { name: 'Karen Carpenter', band: 'The Carpenters', born: 1950 },
  { name: 'Kurt Cobain', band: 'Nirvana', born: 1967 },
  { name: 'Stevie Nicks', band: 'Fleetwood Mac', born: 1948 },
];

function compareValues(key, order = 'asc') {
  return function innerSort(a, b) {
    if (!a.hasOwnProperty(key) || !b.hasOwnProperty(key)) {
      // property doesn't exist on either object
      return 0;
    }

    const varA = (typeof a[key] === 'string')
      ? a[key].toUpperCase() : a[key];
    const varB = (typeof b[key] === 'string')
      ? b[key].toUpperCase() : b[key];

    let comparison = 0;
    if (varA > varB) {
      comparison = 1;
    } else if (varA < varB) {
      comparison = -1;
    }
    return (
      (order === 'desc') ? (comparison * -1) : comparison
    );
  };
}

И вот как вы бы это использовали:

 // array is sorted by band, in ascending order by default
singers.sort(compareValues('band'));

// array is sorted by band in descending order
singers.sort(compareValues('band', 'desc'));

// array is sorted by name in ascending order
singers.sort(compareValues('name'));

// array is sorted by date if birth in descending order
singers.sort(compareValues('born', 'desc'));

Попробуйте это

В приведенном выше коде метод hasOwnProperty используется для проверки того, определено ли указанное свойство для каждого объекта и не было ли оно унаследовано через цепочку прототипов. Если он не определен для обоих объектов, функция возвращает 0

Оператор typeof также используется для проверки типа данных значения свойства. Это позволяет функции определить правильный способ сортировки массива. Например, если значением указанного свойства является stringtoUpperCase

Вы можете настроить вышеупомянутую функцию для учета других типов данных и любых других потребностей вашего скрипта.

String.prototype.localeCompare ()

В нашем примере выше мы хотим иметь возможность сортировать массив объектов, значениями которых являются либо строки, либо числа. Однако, если вы знаете, что будете иметь дело только с объектами, значениями которых являются строки, вы можете немного привести в порядок код с помощью метода JavaScript localeCompare

Этот метод возвращает число, указывающее, идет ли строка до, после или совпадает с заданной строкой в ​​порядке сортировки. Это позволяет без учета регистра сортировать массив:

 ['bjork', 'Bjork', 'Björk'].sort();
// [ 'Bjork', 'Björk', 'bjork' ]

['bjork', 'Bjork', 'Björk'].sort((a, b) => a.localeCompare(b));
//  [ 'bjork', 'Bjork', 'Björk' ]

С точки зрения нашей функции compareValues

 function compareValues(key, order = 'asc') {
  return function innerSort(a, b) {
    if (!a.hasOwnProperty(key) || !b.hasOwnProperty(key)) return 0;
    const comparison = a[key].localeCompare(b[key]);

    return (
      (order === 'desc') ? (comparison * -1) : comparison
    );
  };
}

Вы можете прочитать больше о localeCompare на MDN .

Вывод

Итак, у вас есть это — краткое введение в сортировку массива объектов с использованием ванильного JavaScript. Хотя многие библиотеки предлагают такую возможность динамической сортировки, как показано, не так уж сложно реализовать эту функцию самостоятельно. Плюс хорошо понимать, что происходит под капотом.