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