array.prototype.with 是 es2023 新增的不可变数组方法,用于安全替换单个索引元素;它不修改原数组,仅接受数字索引和新值两个参数,越界或负数索引会抛出 rangeerror。

Array.prototype.with 是什么,它能直接替换索引元素吗
Array.prototype.with 是 ES2023 新增的不可变数组方法,专为「安全替换单个索引值」设计。它不修改原数组,而是返回一个新数组,且只在指定索引位置更新值,其余元素完全保持引用不变(浅拷贝)。
它不是通用“查找并替换”,也不支持条件匹配或多个索引——只接受两个参数:index 和 value。越界索引会抛出 RangeError,这点和 at() 不同。
常见错误现象:用负数索引(如 -1)直接调用,结果报错;或误以为它支持对象键名查找,实际只认数字索引。
怎么正确使用 with 替换第 2 个元素(索引 1)
确保索引合法(非负整数、小于数组长度),传入新值即可:
const arr = ['a', 'b', 'c']; const newArr = arr.with(1, 'x'); console.log(newArr); // ['a', 'x', 'c'] console.log(arr); // ['a', 'b', 'c'] ← 原数组未变
- 索引必须是整数,
1.0或Math.floor(1)都可以,但'1'会隐式转为数字,不推荐依赖类型转换 - 如果索引等于
arr.length,会扩展数组(类似push),但仅限于末尾追加一个元素 - 索引为
arr.length + 1或更大时,直接抛出RangeError: Invalid index
和 slice + spread 的写法比,with 有什么优势
传统写法:[...arr.slice(0, i), newValue, ...arr.slice(i + 1)] 可读性差、创建多个中间数组、性能略低。
with 更简洁、语义明确,且引擎可做优化(V8 已对 with 做了专门的快速路径):
- 避免重复切片,内存分配更少
- 对稀疏数组行为更一致(
slice会丢弃空槽,with保留) - 不触发 getter/setter(如果数组被代理,
slice可能意外触发副作用,with更纯净)
但注意:目前 Safari 16.4+、Chrome 111+、Firefox 114+ 支持,Node.js 20.1+ 启用 —— 旧环境需 polyfill 或降级。
容易忽略的边界情况:替换最后一个元素、空数组、索引 0
这些场景看似简单,但容易踩坑:
- 替换最后一个元素:用
arr.with(arr.length - 1, newVal),别手快写成arr.length(那会追加) - 空数组调用
[].with(0, 'x')→ 报错,因为0 >= [].length(即0 >= 0)不成立,实际要求index ,所以空数组无法用 <code>with插入首个元素 - 索引 0 是完全合法的:
['a','b'].with(0, 'z')返回['z','b'],无特殊处理 - 如果数组有
Symbol.isConcatSpreadable: false等自定义属性,with仍能正常工作,而 spread 写法可能失效
真正要注意的是:它只解决「已知索引」的单点替换。如果你要根据值找索引再替换,得先用 indexOf 或 findIndex,再把结果传给 with —— 这两步不能合并,也没有内置 shortcut。










