数组浅拷贝问题:为何修改首个子数组会影响所有子数组?
问题:修改数组中第一个子数组,所有子数组同步变化
我创建了一个包含子数组的数组,想要移除第一个子数组的首个元素(使用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
相关产品推荐
相关产品推荐

