array.prototype.with是es2023引入的不可变单点替换方法,语法为arr.with(index, value),支持负索引,越界抛rangeerror,不修改原数组且语义清晰、性能更优。

Array.prototype.with 是 ECMAScript 2023(ES14)引入的原生方法,专为**不可变地替换数组中指定索引处的元素**而设计。它不修改原数组,而是返回一个新数组,完美契合函数式编程中的不可变原则。
核心用法:直接替换指定索引的值
语法简洁明确:arr.with(index, value)。
-
index:要替换的元素下标(支持负索引,如
-1表示最后一个) -
value:要插入的新值(可以是任意类型,包括
undefined或null) - 若
index超出范围(如大于等于length或小于-length),会抛出RangeError
例如:
const original = [10, 20, 30];const updated = original.with(1, 25);
console.log(original); // [10, 20, 30](未改变)
console.log(updated); // [10, 25, 30](新数组)
与常见替代方案对比:为什么 with 更合适
过去常用 [...arr.slice(0, i), newValue, ...arr.slice(i + 1)] 或 Object.assign([], arr, {[i]: newValue}),但它们存在缺陷:
- 可读性差:展开运算符链冗长,尤其处理边界时逻辑复杂
-
性能开销大:多次切片创建中间数组;
Object.assign在稀疏数组或含访问器属性时行为不可靠 - 语义模糊:不是为“替换”这个意图设计,容易误解或误用
with() 明确表达「替换第 i 项」,且引擎可针对性优化(如 V8 已实现高效内部实现)。
实用注意事项与边界情况
使用时需留意以下关键细节:
- 仅替换**单个**索引位置——不支持批量替换或多索引操作
- 对
undefined元素有效:[1, undefined, 3].with(1, 'a')→[1, 'a', 3] - 负索引从末尾计数:
[1,2,3].with(-1, 99)→[1,2,99] - 不触发 getter/setter,也不保留原型链上的自定义属性(它返回标准
Array实例)
兼容性与降级建议
目前(截至 2024 年中)已获 Chrome 111+、Firefox 114+、Safari 16.4+ 原生支持。如需兼容旧环境:
- 现代项目推荐使用 Babel(搭配
@babel/preset-env和core-js自动 polyfill) - 手动降级可封装为工具函数:
const withIndex = (arr, i, v) => Object.assign([], arr, {[i]: v}),但注意该方式在稀疏数组中表现不同(with会保持稀疏性,Object.assign会填充空槽为undefined)










