使用 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 展示了如何在 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)

其他新的不可变方法

另外三种方法最近变得具有互操作性:

根据 MDN,这三种方法为其对应项的复制版本。这些方法还可在需要或不可变的情况下使用。

总而言之,使用本文中介绍的四种方法之一,可以在 JavaScript 中更轻松地实现不可变更新。具体而言,使用 .with() 方法可以更轻松地更新数组的单个元素,而无需更改原始数组。