使用 Array.prototype.with 更新不可变数组

庆祝:此功能现已在所有三个主要浏览器引擎中可用!

浏览器最近获得了一种新的可互操作方法,您可以在数组上调用它:Array.prototype.with()

Browser Support 浏览器支持:

  • chrome 110
  • Edge 110
  • firefox 115
  • Safari 16

本文探讨了此方法的工作原理以及如何使用它来更新数组而不改变原始数组。

Array.prototype.with(index, value) 简介

Array.prototype.with(index, value) 方法返回所调用的数组的副本,并将 index 设置为您提供的新 value

以下示例显示年龄数组。您想要创建数组的新副本,同时将第二个年龄从 15 更改为 16:

js 复制代码
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

这就是你如何通过修改来创建一个新的数组副本。

当您想要确保原始数组保持不变时,这非常有用,本文介绍了这方面的一些用例。但是,现在看看如果使用括号表示法会发生什么:

js 复制代码
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

因此,开发人员经常不得不使用其他返回数组副本的方法,从而牺牲了代码的可读性:

js 复制代码
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 中结合 useState 使用 .with() 来永久更新项目数组:

js 复制代码
import React, {useState} from 'https://esm.sh/[email protected]'
import ReactDOM from 'https://esm.sh/[email protected]'


function App() {
    const [items, setItems] = useState(["Item 1", "Item 2", "Item 3"]);

    const updateItem = (index) => {
        // Immutable update
        setItems(items.with(index, `Updated item ${index + 1}`));
    };

    return (
        <ul>
            {items.map((item, index) => (
                <li key={index} className="item">
                    <button onClick={() => updateItem(index)}>Update</button>
                    <span>{item}</span>
                </li>
            ))}
        </ul>
    );
}

ReactDOM.render(<App />,
document.getElementById("root"))

由于 .with() 方法返回数组的副本,因此您可以链接多个 .with() 调用甚至其他数组方法。以下示例演示了从数组中递增第二个和第三个年龄:

js 复制代码
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() 方法可以更轻松地更新数组的单个元素,而无需更改原始数组。


web.developers.google.cn/blog/array-...

相关推荐
旧味清欢|几秒前
关注分离(Separation of Concerns)在前端开发中的实践演进:从 XMLHttpRequest 到 Fetch API
javascript·http·es6
热爱编程的小曾18 分钟前
sqli-labs靶场 less 8
前端·数据库·less
gongzemin29 分钟前
React 和 Vue3 在事件传递的区别
前端·vue.js·react.js
Apifox42 分钟前
如何在 Apifox 中通过 Runner 运行包含云端数据库连接配置的测试场景
前端·后端·ci/cd
-代号95271 小时前
【JavaScript】十四、轮播图
javascript·css·css3
树上有只程序猿1 小时前
后端思维之高并发处理方案
前端
庸俗今天不摸鱼2 小时前
【万字总结】前端全方位性能优化指南(十)——自适应优化系统、遗传算法调参、Service Worker智能降级方案
前端·性能优化·webassembly
QTX187302 小时前
JavaScript 中的原型链与继承
开发语言·javascript·原型模式
黄毛火烧雪下2 小时前
React Context API 用于在组件树中共享全局状态
前端·javascript·react.js
Apifox2 小时前
如何在 Apifox 中通过 CLI 运行包含云端数据库连接配置的测试场景
前端·后端·程序员