, чтобы сохранить свой прогресс
Обьясните, как работают эти '(a, b) => a - b' костыли для функции sort()? И, есть ли нормальная, полноценная функция для сортировки по вознастанию?
Сергей, '(a, b) => a - b' - это не костыль для sort(), это просто один из вариантов функции, используемой для сортировки. И этот вариант даже представлен в документации MDN на странице Array.prototype.sort().
Но давайте все-таки разберемся, потому что тема действительно малопонятная.
Для начала сразу определимся, что '(a, b) => a - b' - это стрелочная функция, которая может быть передана в sort() как параметр и используется для того, чтобы задать пользовательский сценарий сортировки. Зачем это может быть нужно?
1. По умолчанию (если не задать свой собственный обработчик), сравнение элементов массива происходит в строковом формате. То есть даже если массив у нас содержит только цифры, отсортированы они будут как строки. Пример:
Как видим, в результате 10 типа меньше, чем 2, но это все потому что сравниваются строки, а если рассматривать первые символы строк '10' и '2', то '1' меньше, чем '2'.
Вот в таком случае, нам нужно передать функцию-сортировщик, которая будет сравнивать именно как цифры. В нашем случае пример такой:
То есть здесь мы уже более четкие условия задаем: Если a меньше b, то возвращаем -1, если a больше b, то возвращаем +1, иначе возвращаем 0. Таким образом и определяется сортировка: поставить элемент перед, после, или оставить на месте. Но при этом не обязательно возвращать именно -1, +1 или 0, достаточно меньше нуля, больше нуля или равно нулю. В этом как раз и кроется смысл сокращенной формы a - b. Ведь при вычетании b из a, результат как раз и получится положительный, отрицательный или нулевой.
2. Если у нас более сложная структура элементов. К примеру, это объекты и мы хотим отсортировать их по какому-то полю. Например:
Уточнение: данная функция-сортировщик вызывается не один раз, а для каждой пары перечисляемых элементов массива, пока массив не будет отсортирован полностью. К примеру, возьмем простой массив с уникальными числами:
Как видим, элемента 3, а функция сортировки была вызвана два раза (потому что 1 и 2 элементы, потом 2 и 3, и все они были однозначно отсортированы больше/меньше).
А вот посмотрим теперь такой пример:
Вот здесь уже 4 вызова, хотя элементов в массиве все так же 3. Это потому что в отдельные итерации результат разницы был нулевой и элементы оставались на своих местах, но потом их надо было сравнить с другими элементами.
Это несколько запутанно, но стоит все-таки просто уяснить этот момент с множественным вызовом функции-параметра. Такое много где используется, например в функциях Array.filter(), Array.map(), Array.reduce() и т.п.
Из этих выводов:
/* 2 1
1 2
1 2
1 1
*/
хочу уточнить, 'a' и 'b' это 'следующий' и 'предыдущий' элементы масива?
Да, два сравниваемых элемента массива. Но как я и показал в последних примерах, это не всегда именно рядом стоящие. То есть начинается всегда с 1 и 2 элементов, но если в процессе есть такие, которые равны друг другу, то могут потом сравниваться и не соседние элементы. Но в общих чертах так.