В браузерах недавно появился новый совместимый метод, который можно вызывать для массивов: Array.prototype.with() .
В этой статье рассматривается принцип работы данного метода и способы его использования для обновления массива без изменения исходного массива.
Введение в 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() упрощает обновление одного элемента массива без изменения исходного массива.