用展开运算符实现数组末尾非变异替换的核心是构造新数组:[...arr.slice(0, -1), newLast],兼容空数组和单元素数组;解构写法 const [...head, \_] = arr; [...head, newLast] 更语义化;避免追加后截断等低效或变异操作。

用展开运算符(...)实现数组末尾元素的非变异替换拷贝,核心思路是:**不修改原数组,而是构造一个新数组,保留前面所有元素,仅将最后一个位置替换成新值**。
基础写法:展开 + 最后一个新元素
假设原始数组为 arr,想把末尾元素替换成 newLast,可直接写:
[...arr.slice(0, -1), newLast]
说明:arr.slice(0, -1) 取出除最后一个外的所有元素(不改变原数组),再用展开运算符铺开,最后拼上新元素。这是最直观、兼容性好(支持所有现代环境)的方式。
更简洁写法:解构 + 展开(ES2015+)
若已知数组长度 ≥ 1,可用解构语法提取“除最后一个外的部分”:
-
[...arr.slice(0, -1), newLast]等价于[...([...arr].slice(0, -1)), newLast] - 但更推荐解构形式:
const [...head, _] = arr; const newArr = [...head, newLast];
注意:解构赋值本身不改变原数组,head 是新数组,_ 接收原末尾元素(可忽略)。这种方式语义清晰,适合逻辑较重的场景。
边界情况处理:空数组或单元素数组
上述方法在 arr = [] 或 arr = [x] 时依然安全:
-
[].slice(0, -1)→[],结果为[newLast] -
[1].slice(0, -1)→[],结果为[newLast] -
[1, 2].slice(0, -1)→[1],结果为[1, newLast]
无需额外判断长度,slice(0, -1) 天然支持边界。
不推荐的误区写法
以下方式看似简洁,但存在隐患:
-
[...arr, newLast].slice(0, -1)—— 先追加再截断,逻辑绕且低效 -
arr.concat(newLast).slice(0, -1)—— 同样多一次拼接,且concat对嵌套数组有特殊行为 - 直接修改
arr[arr.length - 1] = newLast—— 这是变异操作,违反“非变异”要求
应始终以“构造新数组”为出发点,避免中间冗余步骤。

















