You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

数组浅拷贝问题:为何修改首个子数组会影响所有子数组?

问题:修改数组中第一个子数组,所有子数组同步变化

我创建了一个包含子数组的数组,想要移除第一个子数组的首个元素(使用arr[0].shift()),但运行代码后,所有子数组的首个元素都被移除了。我猜测这和fillWith的拷贝方式有关,尝试了多种浅拷贝方法但都无效,请问忽略了什么?

let arr= Array(3)        
let fillWith = Array.from({length: 5}, (_, i) => i+1);

arr.fill([...[], ...fillWith]) // Try 1
//arr.fill(fillWith.slice()) // Try 2


console.log(arr) // -> [[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]]

arr[0].shift();

console.log(arr)
/* 
期望结果 -> [[2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]]
实际结果 -> [[2, 3, 4, 5], [2, 3, 4, 5], [2, 3, 4, 5]]
*/

原因分析

问题核心是**Array.fill()处理引用类型时,会填充同一个对象引用**。

你做的[...fillWith]或fillWith.slice()确实是对fillWith的浅拷贝,但这个拷贝后的数组是同一个对象。arr.fill(这个拷贝数组)会把该数组的引用重复赋值给arr的每一个索引位置,导致arr[0]、arr[1]、arr[2]指向的是内存中同一个数组对象。因此修改其中任何一个,另外两个都会同步变化。


解决方案

要让每个子数组都是独立对象,需要为arr的每个位置单独创建新的数组拷贝,而非填充同一个引用。以下是几种可行方法:

方法1:使用Array.from生成数组

let fillWith = Array.from({length: 5}, (_, i) => i+1);
// 为每个位置生成新的拷贝数组
let arr = Array.from({length: 3}, () => [...fillWith]);

arr[0].shift();
console.log(arr);
// 输出:[[2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]]

方法2:使用map初始化(处理稀疏数组)

let fillWith = Array.from({length: 5}, (_, i) => i+1);
// Array(3)是稀疏数组,用Array.from转为密集数组后再map
let arr = Array.from(Array(3)).map(() => fillWith.slice());

arr[0].shift();
console.log(arr);
// 输出符合预期

方法3:手动循环填充

let fillWith = Array.from({length: 5}, (_, i) => i+1);
let arr = [];
for (let i = 0; i < 3; i++) {
  // 每次循环都创建新的数组拷贝
  arr.push([...fillWith]);
}

arr[0].shift();
console.log(arr);
// 输出符合预期

内容的提问来源于stack exchange,提问作者Soerman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 14:31:02