copyWithin 不创建新数组且不触发内存重分配,直接在原数组内移动元素,因此高性能;其参数 target、start、end 均为索引(支持负数),target 是复制目标起始位,start/end 为源区间(左闭右开),重叠时自动按方向避免覆盖。

copyWithin 不会创建新数组,也不触发内存重分配,它直接在原数组内部移动元素——这是它高性能的根本原因。但位移方向、边界越界和目标重叠处理稍有不慎,结果就和预期相反。
copyWithin 的三个参数怎么填才不踩坑
调用形式是 arr.copyWithin(target, start, end),三者全是索引,且都支持负数(从末尾倒数)。关键点在于:
-
target是复制“目的地”的起始位置,不是插入位置;若target超出数组长度,操作仍会执行(可能静默截断) -
start和end定义要复制的源片段,end是左闭右开区间(即不包含end本身) - 当
target < start(前移),或target > start(后移),只要源与目标区域重叠,copyWithin内部按“从左到右”或“从右到左”自动调整拷贝顺序,避免覆盖污染——这点不用手动干预,但得理解它怎么选方向
前移元素(比如删除开头 2 个,后面全部前挪)
常见场景:模拟 shift 多次,但不想反复修改 length 或触发 GC。例如把 [1,2,3,4,5] 变成 [3,4,5,4,5](删前两个,剩余前移):
const arr = [1,2,3,4,5]; arr.copyWithin(0, 2); // target=0, start=2, end=arr.length → 复制索引2开始到末尾,贴到0起
注意:copyWithin 不改变数组长度,所以原数组还是 5 个元素,只是前两个被覆盖了。如果真要“删除”,还得配合 length 截断:
arr.length = arr.length - 2;
后移并留空(比如为插入腾位置)
想在索引 2 处插入新元素,需先把 [2...] 后移一位。错误写法:arr.copyWithin(3, 2) —— 这会让索引 2 的值跑到 3,但原来 3 的值还在,没被推走。正确做法是反向指定范围:
- 先确保数组有足够空间(如用
push扩容,或提前length++) - 用
arr.copyWithin(3, 2, arr.length-1):把[2 ... 倒数第二个]复制到[3 ... 末尾],给索引 2 腾出空位
负索引在这里很实用:想把最后 3 个元素移到开头,写 arr.copyWithin(0, -3) 即可,无需算绝对位置。
浏览器兼容性与 TypedArray 的行为差异
所有现代浏览器都支持 copyWithin(包括 IE11+),但 TypedArray(如 Uint8Array)的行为和普通数组完全一致,可放心迁移。唯一要注意的是:
- 普通数组允许稀疏区域(如
arr[10] = 1后arr.length === 11,但中间为空),copyWithin会把undefined当作真实值复制过去 -
TypedArray没有稀疏概念,未赋值位置默认是 0,复制时也传 0 - 性能上,
TypedArray.copyWithin在大量数值运算中更快,因为无类型转换开销
真正容易被忽略的是:当 target 为负数且绝对值大于数组长度时,它会被归零(即 Math.max(0, target)),而 start/end 负数则按正常模运算处理——这个不对称性在动态计算索引时可能引发静默偏差。


















