Поиск и сортировка
Здесь будет встроен видео-разбор темы (5–7 минут, YouTube / RuTube / VK Видео) — тем, кто лучше воспринимает на слух, текст ниже не обязателен.
Массив хранит порядок, но не знает, что вам в нём нужно. Поиск и сортировка — два способа задать вопрос: find отвечает «вот этот элемент», sort — «вот в таком порядке».
find перебирает массив и возвращает первый элемент, на котором ваша функция вернула истину. Не список, не индекс — сам элемент. Как только совпадение найдено, перебор останавливается: остальные элементы даже не проверяются.
findIndex устроен так же, но отдаёт позицию. Разница особенно заметна, когда ничего не нашлось: find вернёт undefined, а findIndex — -1. Проверять результат find проще: индекс 0 — вполне рабочая позиция, но в условии он ведёт себя как ложь, и на этом легко ошибиться.
Иногда нужно последнее совпадение, а не первое. Для этого есть findLast и findLastIndex — те же методы, но перебор идёт с конца.
Когда нужен не сам элемент, а ответ «да» или «нет», берут includes — он возвращает true или false. indexOf отвечает подробнее: позицией, а если не нашёл — привычным -1.
Оба ищут совпадение значения, а не условие — функцию им передать нельзя, для этого есть find. Объекты они сравнивают по ссылке: одинаковые на вид, но разные объекты для них не равны. И одна историческая мелочь: indexOf не умеет находить NaN, а includes умеет.
У sort есть поведение по умолчанию, на которое попадаются почти все. Без аргументов он приводит элементы к строкам и сравнивает их посимвольно — как слова в словаре.
Строка «10» начинается с единицы, поэтому встаёт раньше «5», а «100» опережает «25». Для чисел это почти никогда не то, что нужно. У строк своя особенность: сравниваются коды символов, а не буквы алфавита, — поэтому заглавные оказываются раньше строчных.
Лечится это одним приёмом: передайте в sort функцию двух аргументов — компаратор. Он получает пару элементов и возвращает число, а sort по знаку этого числа решает, кого поставить раньше.
| Что вернул компаратор | Как поступит sort |
|---|---|
| Отрицательное число | a встанет раньше b |
| Положительное число | b встанет раньше a |
| Ноль | порядок этой пары не изменится |
Отсюда классическое (a, b) => a - b для возрастания: если a меньше, разность отрицательная — значит, a уходит вперёд. Поменяли местами, b - a, и получили убывание. Объекты сортируются так же, только сравнивают нужное поле.
Строки вычитанием не сравнить — получится NaN. Для них есть localeCompare: он возвращает те же отрицательное, ноль или положительное, но по правилам языка, с учётом алфавита и регистра.
Деление методов на меняющие массив и возвращающие новый уже встречалось в статье «Методы массивов: map, filter, reduce»; у сортировки оно бьёт больнее всего. sort и reverse работают «на месте»: они перестраивают тот самый массив, который вы им дали, и возвращают его же. Если исходный порядок ещё понадобится, сначала сделайте копию — например, спредом.
const sorted = arr.sort() — это не копия, а второе имя для того же массива.
У этих методов есть копирующие двойники — toSorted и toReversed. Аргументы те же, но оригинал остаётся нетронутым. Они появились в 2023 году, так что в очень старых окружениях их может не быть — там выручает копия через спред.
| Меняет массив | Возвращает новый | Что делает |
|---|---|---|
| sort | toSorted | упорядочивает элементы |
| reverse | toReversed | переворачивает порядок |
| splice | toSpliced | вырезает и вставляет |
- find возвращает первый подходящий элемент, findIndex — его позицию; при неудаче это undefined и -1.
- includes отвечает true или false, indexOf — индексом или -1; оба ищут значение, а не условие.
- sort без аргументов сравнивает элементы как строки, поэтому 10 оказывается раньше 5.
- Компаратор (a, b) => a - b задаёт порядок по знаку числа: отрицательное — a раньше, положительное — b раньше.
- sort и reverse меняют исходный массив, toSorted и toReversed возвращают копию.
1/3Что окажется в массиве после [2, 10, 1].sort()?
2/3findIndex ничего не нашёл. Что он вернёт?
3/3Какой вызов оставит исходный массив нетронутым?
Отсортировать копию, не тронув оригинал
Выведите баллы по убыванию, но так, чтобы исходный массив scores остался в прежнем порядке.
Сначала копия спредом, потом сортировка компаратором b - a — от большего к меньшему.
То же самое одной строкой даёт scores.toSorted((a, b) => b - a) — этот метод копирует сам. А вот scores.sort((a, b) => b - a) без копии переставит исходный массив, и вторая проверка провалится.
Есть ли слово и какое подойдёт
Проверьте, есть ли в массиве слово «кот», и найдите первое слово длиннее пяти букв.
includes отвечает на вопрос «есть ли», find — «какой именно».
Обратите внимание: includes не принимает функцию, а find — наоборот, работает только с ней. И если подходящего слова не найдётся, find вернёт undefined, так что результат стоит проверить перед тем, как что-то у него запрашивать.