浏览器最近新增了一种可互操作的方法,您可以在数组上调用该方法: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 示例展示了如何在 React 中结合使用 .with() 和 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() 方法可让您更轻松地更新数组的单个元素,而无需更改原始数组。