使用 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/react@18.2.0'
import ReactDOM from 'https://esm.sh/react-dom@18.2.0'


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-...

相关推荐
web小白成长日记1 小时前
企业级 Vue3 + Element Plus 主题定制架构:从“能用”到“好用”的进阶之路
前端·架构
APIshop1 小时前
Python 爬虫获取 item_get_web —— 淘宝商品 SKU、详情图、券后价全流程解析
前端·爬虫·python
风送雨1 小时前
FastMCP 2.0 服务端开发教学文档(下)
服务器·前端·网络·人工智能·python·ai
XTTX1101 小时前
Vue3+Cesium教程(36)--动态设置降雨效果
前端·javascript·vue.js
LYFlied2 小时前
WebGPU与浏览器边缘智能:开启去中心化AI新纪元
前端·人工智能·大模型·去中心化·区块链
Setsuna_F_Seiei3 小时前
2025 年度总结:人生重要阶段的一年
前端·程序员·年终总结
model20053 小时前
alibaba linux3 系统盘网站迁移数据盘
java·服务器·前端
han_4 小时前
从一道前端面试题,谈 JS 对象存储特点和运算符执行顺序
前端·javascript·面试
aPurpleBerry4 小时前
React 01 目录结构、tsx 语法
前端·react.js
jayaccc4 小时前
微前端架构实战全解析
前端·架构