Обновления неизменяемого массива с помощью Array.prototype.with

Недавно в браузерах появился новый совместимый метод, который можно вызывать для массивов: Array.prototype.with() .

Поддержка браузера

  • Хром: 110.
  • Край: 110.
  • Фаерфокс: 115.
  • Сафари: 16.

Источник

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

Введение в Array.prototype.with(index, value)

Метод Array.prototype.with(index, value) возвращает копию вызванного им массива с index , установленным в новое предоставленное вами value .

В следующем примере показан массив возрастов. Вы хотите создать новую копию массива, изменив второй возраст с 15 на 16:

const ages = [10, 15, 20, 25];

const newAges = ages.with(1, 16);
console.log(newAges); // [10, 16, 20, 25]
console.log(ages); // [10, 15, 20, 25] (unchanged)

Разбивка кода: ages.with(...) возвращает копию переменной ages без изменения исходного массива. ages.with(1, …) заменяет второй элемент ( index = 1 ). ages.with(1, 16) присваивает второму элементу значение 16 .

Вот как вы смогли создать новую копию массива с модификацией.

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

const ages = [10, 15, 20, 25];

const newAges = ages;
newAges[1] = 16;
console.log(newAges); // [10, 16, 20, 25]
console.log(ages); // [10, 16, 20, 25] (Also changed 🙁)

Как видите, в этом примере также была изменена переменная ages . Это потому, что когда вы назначаете ages = newAges , JavaScript не копирует массив, а создает ссылку на другой массив. Таким образом, любое изменение в одном также повлияет на другое, поскольку они оба указывают на один и тот же массив.

Array.prototype.with() и неизменность

Неизменяемость лежит в основе многих интерфейсных библиотек и фреймворков, среди которых можно назвать React (и Redux) и Vue.

Кроме того, другие библиотеки и фреймворки не обязательно требуют неизменяемости, но поощряют ее для повышения производительности: Angular и Lit.

Поэтому разработчикам часто приходилось использовать другие методы, возвращающие копии массивов, что жертвовало читабельностью кода:

const ages = [10, 15, 20, 25];

const newAges = ages.map((age, index) => {
    if (index === 1) {
         return 16;
    }
    return age;
});

console.log(newAges); // [10, 16, 20, 25]
console.log(ages); // [10, 15, 20, 25] (Remains unchanged)

Вот пример Codepen того, как .with() можно использовать в React в сочетании с useState для неизменного обновления массива элементов:

Поскольку метод .with() возвращает копию массива, вы можете объединить несколько вызовов .with() или даже других методов массива. В следующем примере показано увеличение второго и третьего возраста из массива:

const ages = [10, 15, 20, 25];

const newAges = ages.with(1, ages[1] + 1).with(2, ages[2] + 1)

console.log(newAges); // [10, 16, 21, 25]
console.log(ages); // [10, 15, 20, 25] (unchanged)

Другие новые неизменяемые методы

Недавно стали совместимыми три других метода:

  • Array.prototype.toReversed() , который переворачивает массив без изменения исходного массива.
  • Array.prototype.toSorted() , который сортирует массив без изменения исходного массива.
  • Array.prototype.toSpliced() , который работает как .splice() , но без изменения исходного массива.

По мнению MDN, эти три метода являются копирующей версией своих аналогов. Эти методы также можно использовать там, где ожидается или предпочтительна неизменность.

В заключение отметим, что неизменяемых обновлений в JavaScript можно легче добиться с помощью одного из четырех методов, представленных в этой статье. В частности, метод .with() упрощает обновление одного элемента массива без изменения исходного массива.