Введение
В данной статье мы обсудим новые возможности работы с массивами в JavaScript, которые были добавлены в ES2023.
findLast и findLastIndex
Допустим, у нас есть массив с элементами:
const arr = [0, 1, 2, 3, 7];
Нам нужно найти элемент со значением 7, и мы предполагаем, что он находится ближе к концу массива.
В предыдущем варианте когда мы использовали find(), мы бы делали это следующим образом:
const arr = [0, 1, 2, 3, 7];
const res = arr.find(el => {
console.log('Поиск');
return el == 7;
})
// 5 раз будет выведено в консоли слово "Поиск"
Это может быть нормально для небольших массивов, но если массив большой и вы знаете, что элемент находится ближе к концу, то можно использовать метод findLast(), который находит первый элемент с конца, удовлетворяющий условию:
const arr = [0, 1, 2, 3, 7];
const res = arr.findLast(el => {
console.log('Поиск');
return el == 7;
})
// вывод в консоль: Поиск
В этом случае вывод будет происходить только 1 раз.
Аналогично существует метод findLastIndex(), который ищет индекс элемента, удовлетворяющего определённому условию.
UPD: По просьбе из комментариев даю более точную формулировку:
FindLast обходит массив с конца, возвращая первый элемент, который удовлетворяет переданной в метод функции (или undefined, если не нашел).
Потому если в массиве несколько одинаковых элементов, find и findLast вернут разные значения.
Методы не изменяющие исходный массив
Большинство методов работы с массивами в JavaScript изменяют исходный массив вместо создания нового. Например, это может вызвать проблемы в React, когда необходимо изменить состояние и создать новый массив. Мы рассмотрим, как это решается в последней версии спецификации ES2023 и в JavaScript. Потому ниже мы рассмотрим новые методы, которые позволяют этого избежать.
with
Предположим, нам нужно:
Взять массив
Изменить его элемент
Создать новый массив
Теперь с помощью метода with() мы можем это сделать гораздо проще. Нам нужно передать индекс, на котором мы хотим заменить элемент, а затем значение этого элемента:
const a = [1, 3, 5]
const arrNew = a.with(1, 'test');
console.log(a); // вывод: [1, 3, 5]
console.log(arrNew); // вывод: [1, 'test', 5]
Метод with() копирует исходный массив, меняет один элемент и возвращает новый массив с измененным элементом по указанному индексу.
toSorted
Метод toSorted() сортирует элементы массива так же, как и метод sort(), но возвращает новый массив:
const a = [2, 3, 6, 1];
const b = a.toSorted();
console.log(a) // вывод: [2, 3, 6, 1]
console.log(b) // вывод: [1, 2, 3, 6]
toReversed
Метод toReversed() меняет порядок элементов в массиве на обратный, как и метод reverse(), но возвращает новый массив:
const a = [2, 3, 6, 1];
const c = a.toReversed();
console.log(a) // вывод: [2, 3, 6, 1]
console.log(c) // вывод: [1, 6, 3, 2]
toSpliced
Метод toSpliced() является копией метода splice(), но возвращает новый массив:
const a = [2, 3, 6, 1];
const d = a.toSpliced(0, 1);
console.log(a) // вывод: [2, 3, 6, 1]
console.log(d) // вывод: [3, 6, 1]
Комментарии (19)
Format-X22
15.07.2023 13:46+2Иммутабельность массивов хороша для недопуска ошибок, но каждый раз заставляет пользователя докупать ещё одну планку памяти.
iliazeus
15.07.2023 13:46В любых современных JS-движках поколенческий GC, который соберёт такие короткоживущие массивы почти забесплатно.
Format-X22
15.07.2023 13:46+1Память по пути всё равно выделится. А в синхронном цикле до окончания прохода эвент лупа можно насобирать таких клонов вообще прилично, особенно если оно там каскадно дальше пойдёт и сверху цепочки вызовов функций где каждый раз такой иммутабельный слайс/фильтр/мэп по одному проходу на каждую функцию. GC придёт и всех убьёт, но в конце. В этом поинт, не в утечке памяти.
Возможно, есть какой-либо архитектурный выход из ситуации где не нужен бы был клон списков значений? Но пока увы.
iliazeus
15.07.2023 13:46Я в целом с вами не спорю про вред излишних копирований :) Просто немного удивился, что в первую очередь вспомнили про пямять, а не про время.
синхронном цикле до окончания прохода эвент лупа можно насобирать таких клонов вообще прилично
Я вот кстати не уверен, что GC просто не вклинится в середину итерации эвент-лупа. Но утверждать не буду.
Opaspap
15.07.2023 13:46если у вас такой большой синхронный цикл с таким множественным выделением памяти, то вы что-то делаете не так (например неправильно выбрали платформу для реализации проекта).
YourDesire
15.07.2023 13:46+1The
find()
method returns the first element in the provided array that satisfies the provided testing function. If no values satisfy the testing function,undefined
is returned.Метод
find
работает не совсем так (а если быть более точным - совсем не так), как вы написали.
`find` вернёт первый попавшийся элемент массива, который удовлетворяет условиям.
`findLast` вернёт последний элемент массива из тех, что удовлетворяет условиям.
Аналогично сfindIndex
иfindLastIndex
, только они, в отличии от первых двух - возвращают индекс элемента массива.
Вы перепутали назначениеfind*
методов, сfilter
.PurpleSchool Автор
15.07.2023 13:46А что здесь не так у меня написано? Я не говорил про filter, который вернёт массив элементов. Я написал, что нам нужно найти 7, как пример поиска элемента по определенному условию.
YourDesire
15.07.2023 13:46Меня ввело в заблуждение то, как использовался
console.log
. С учётомUPD
, которое вы добавили в статью (обход массива начинается с конца), всё встаёт на свои места.
В частности:
> FindLast обходит массив с конца
Ваши примеры верны и понятны на тему того, что вы хотели этими примерами сказать.
Прошу прощения, за досадное недоразумение.
Mertico
15.07.2023 13:46Не совсем корректный пример с findLast он начинает искать с конца и возвращает первое найденое. Результат между find и findLast может быть совершенно разным
Пример в доке: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findLast
PurpleSchool Автор
15.07.2023 13:46-1А почему пример не корректен? Результат может быть действительно разным, если есть повторяющиеся элементы в массиве, но в примере я показал основную задачу данного метода - оптимизировать поиск, если мы знаем, что искомое значение ближе к концу.
dopusteam
15.07.2023 13:46+1но в примере я показал основную задачу данного метода - оптимизировать поиск, если мы знаем, что искомое значение ближе к концу.
Все, что нужно знать о ваших знаниях
dopusteam
Ищет индекс элемента, а не элемент по индексу
Думаю, основное предназначение findLast не в том, чтоб меньше перебирать, а в том, чтоб найти последний, что, собственно, и отражено в названии
PurpleSchool Автор
Исправлено, спасибо. FindLast как раз нужен для обхода с конца. Просто последний элемент можно получить и по индексу или метод at.
dopusteam
Я думал из контекста понятно, что findLatest для поиска последнего по условию.
Нет. Он нужен для поиска последнего элемента, удовлетворяющего условию. Под капотом он может как угодно ходить. Или буду рад ссылке на документацию.
Вы в статье противопоставляете его методу find, что в корне неправильно, т.к. при наличии более одного подходящего элемента они вернут разные элементы
Не исправлено, это неправильное определение
PurpleSchool Автор
Пожалуйста: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findLast
The
findLast()
method iterates the array in reverse order and returns the value of the first element that satisfies the provided testing function.Он не просто выводит последний элемент, который удовлетворят условию, а делает это, проходя массив с конца.
Да, противопоставляю, find ищет первый элемент с начала, а findLast первый элемент с конца.
dopusteam
По поводу прохода согласен.
Этого в статье нет
PurpleSchool Автор
Спасибо за дополнение, добавил