Введение

В данной статье мы обсудим новые возможности работы с массивами в 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)


  1. dopusteam
    15.07.2023 13:46
    +10

    Аналогично существует метод findLastIndex(), который ищет элемент по индексу

    Ищет индекс элемента, а не элемент по индексу

    но если массив большой и вы знаете, что элемент находится ближе к концу, то можно использовать метод findLast

    Думаю, основное предназначение findLast не в том, чтоб меньше перебирать, а в том, чтоб найти последний, что, собственно, и отражено в названии


    1. PurpleSchool Автор
      15.07.2023 13:46

      Исправлено, спасибо. FindLast как раз нужен для обхода с конца. Просто последний элемент можно получить и по индексу или метод at.


      1. dopusteam
        15.07.2023 13:46
        +1

        Я думал из контекста понятно, что findLatest для поиска последнего по условию.

        FindLast как раз нужен для обхода с конца

        Нет. Он нужен для поиска последнего элемента, удовлетворяющего условию. Под капотом он может как угодно ходить. Или буду рад ссылке на документацию.

        Вы в статье противопоставляете его методу find, что в корне неправильно, т.к. при наличии более одного подходящего элемента они вернут разные элементы

        Исправлено, спасибо

        Аналогично существует метод findLastIndex(), который ищет индекс элемента, удовлетворяющего определённому условию

        Не исправлено, это неправильное определение


        1. PurpleSchool Автор
          15.07.2023 13:46

          Пожалуйста: 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 первый элемент с конца.


          1. dopusteam
            15.07.2023 13:46
            +1

            По поводу прохода согласен.

            Да, противопоставляю, find ищет первый элемент с начала, а findLast первый элемент с конца.

            Этого в статье нет


            1. PurpleSchool Автор
              15.07.2023 13:46

              Спасибо за дополнение, добавил


  1. Format-X22
    15.07.2023 13:46
    +2

    Иммутабельность массивов хороша для недопуска ошибок, но каждый раз заставляет пользователя докупать ещё одну планку памяти.


    1. iliazeus
      15.07.2023 13:46

      В любых современных JS-движках поколенческий GC, который соберёт такие короткоживущие массивы почти забесплатно.


      1. Format-X22
        15.07.2023 13:46
        +1

        Память по пути всё равно выделится. А в синхронном цикле до окончания прохода эвент лупа можно насобирать таких клонов вообще прилично, особенно если оно там каскадно дальше пойдёт и сверху цепочки вызовов функций где каждый раз такой иммутабельный слайс/фильтр/мэп по одному проходу на каждую функцию. GC придёт и всех убьёт, но в конце. В этом поинт, не в утечке памяти.

        Возможно, есть какой-либо архитектурный выход из ситуации где не нужен бы был клон списков значений? Но пока увы.


        1. iliazeus
          15.07.2023 13:46

          Я в целом с вами не спорю про вред излишних копирований :) Просто немного удивился, что в первую очередь вспомнили про пямять, а не про время.

          синхронном цикле до окончания прохода эвент лупа можно насобирать таких клонов вообще прилично

          Я вот кстати не уверен, что GC просто не вклинится в середину итерации эвент-лупа. Но утверждать не буду.


        1. Opaspap
          15.07.2023 13:46

          если у вас такой большой синхронный цикл с таким множественным выделением памяти, то вы что-то делаете не так (например неправильно выбрали платформу для реализации проекта).


    1. Akon32
      15.07.2023 13:46

      докупать ещё одну планку памяти

      ...и ядро процессора.


  1. YourDesire
    15.07.2023 13:46
    +1

    The 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.


    1. PurpleSchool Автор
      15.07.2023 13:46

      А что здесь не так у меня написано? Я не говорил про filter, который вернёт массив элементов. Я написал, что нам нужно найти 7, как пример поиска элемента по определенному условию.


      1. YourDesire
        15.07.2023 13:46

        Меня ввело в заблуждение то, как использовался console.log. С учётом UPD, которое вы добавили в статью (обход массива начинается с конца), всё встаёт на свои места.
        В частности:
        > FindLast обходит массив с конца
        Ваши примеры верны и понятны на тему того, что вы хотели этими примерами сказать.
        Прошу прощения, за досадное недоразумение.


        1. PurpleSchool Автор
          15.07.2023 13:46

          Спасибо, благодаря вашем комментариям, я могу улучшать материал)


  1. Mertico
    15.07.2023 13:46

    Не совсем корректный пример с findLast он начинает искать с конца и возвращает первое найденое. Результат между find и findLast может быть совершенно разным

    Пример в доке: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findLast


    1. PurpleSchool Автор
      15.07.2023 13:46
      -1

      А почему пример не корректен? Результат может быть действительно разным, если есть повторяющиеся элементы в массиве, но в примере я показал основную задачу данного метода - оптимизировать поиск, если мы знаем, что искомое значение ближе к концу.


      1. dopusteam
        15.07.2023 13:46
        +1

        но в примере я показал основную задачу данного метода - оптимизировать поиск, если мы знаем, что искомое значение ближе к концу.

        Все, что нужно знать о ваших знаниях