JavaScript生成嵌套数组时所有元素被最后一项覆盖如何解决
二维数组转指定结构三维数组时元素被最后一项覆盖问题
问题复现
现有长度为3的二维数组c2,每个子数组长度为7,需要转换为[3][1][7]结构的三维数组,使用如下代码实现时,返回结果所有子项都被原数组最后一个子数组覆盖:
var c3 = new Array(players).fill(new Array(1).fill(new Array(7))) // 原始c2结构 // c2= [ // [x1, x2, x3, x4, x5, x6, x7], // [y1, y2, y3, y4, y5, y6, y7], // [z1, z2, z3, z4, z5, z6, z7] // ] c2.forEach(function (val, ind) { c3[ind][0] = c2[ind] }) // 预期输出 // [ // [[x1, x2, x3, x4, x5, x6, x7]], // [[y1, y2, y3, y4, y5, y6, y7]], // [[z1, z2, z3, z4, z5, z6, z7]] // ] // 实际输出 // [ // [[z1, z2, z3, z4, z5, z6, z7]], // [[z1, z2, z3, z4, z5, z6, z7]], // [[z1, z2, z3, z4, z5, z6, z7]] // ]
根本原因
Array.fill()传入引用类型值(数组、对象等)时,不会为每个填充位置创建独立副本,所有位置都会指向同一个内存地址的同一个实例。
上述初始化代码中,new Array(1).fill(new Array(7))仅执行了1次,也就是说c3的3个一级元素,本质是同一个长度为1的数组的三个引用。后续遍历赋值时,每次修改c3[ind][0]都是在修改这同一个数组的第0位,最后一次赋值(z数组)会覆盖之前的所有修改,最终所有位置读取到的都是最后一次赋值的结果。
修复方法
初始化多层数组时,要保证每一层的引用类型都是独立创建的,不要直接用fill嵌套填充引用值,有两种简单的实现方式:
方式1:初始化时就创建独立数组实例
用Array.from的映射函数为每个一级元素生成独立数组:
// 初始化时每个一级元素都是新建的独立数组,不存在引用共用 const c3 = Array.from({ length: players }, () => [new Array(7)]) c2.forEach((val, ind) => { c3[ind][0] = val })
方式2:遍历时新建包裹数组
如果不需要提前初始化固定长度的空数组,可以直接在遍历过程中构造每一项的结构:
const c3 = [] c2.forEach(val => { c3.push([val]) // 每一项都新建一个数组包裹当前遍历到的子数组 })
内容的提问来源于stack exchange,提问作者Arya Vaziri
相关产品推荐
相关产品推荐

