数组对象赋值时所有元素同步修改的问题及修复方案
对象数组元素同步修改问题的修复方案
问题描述
我有一个包含数组的嵌套对象,同时存在该对象的数组。当尝试访问并修改该对象数组的第一个元素时,发现数组中所有元素都被同步修改。原代码使用for循环赋值,结果所有元素都变成了数组最后一个元素的值,简化代码排查后,用push方法也出现同样问题。
相关代码如下:
level = Array(heroStatus.length); name = Array(heroStatus.length); levelnum = Array(heroStatus.length); equipped = Array(heroStatus.length); inInventory = Array.from(Array(5), () => new Array(heroStatus.length)); equipmentType = {level,name,levelnum,equipped,inInventory}; let equipment = Array.from(Array(6), () => equipmentType ); i = 0; equipment[0].level = heroStatus.map((x) => x[2+(2*i)]); equipment[0].name = heroStatus.map((x) => x[3+(2*i)]); equipment[0].levelNum = equipment[0].level.map((x) => equipmentLevelNames.findIndex((y)=> y==x )); equipment[0].equipped = heroEquippedItems.map((x) => x[i]); equipment[0].inInventory[0] = equipment[0].level.map((x)=> inventoryItemList.findIndex(y => y[1] == equipment[0].name[equipment[0].level.indexOf(x)] && y[0] == equipment[0].level[equipment[0].level.indexOf(x)])); equipment[0].inInventory[0] = equipment[0].inInventory[0].map((x)=> {if(x ==-1){ return false}else{ return true} }); i = 1; equipment[1].level = heroStatus.map((x) => x[2+(2*i)]); equipment[1].name = heroStatus.map((x) => x[3+(2*i)]); equipment[1].levelNum = equipment[1].level.map((x) => equipmentLevelNames.findIndex((y)=> y==x )); equipment[1].equipped = heroEquippedItems.map((x) => x[i]); equipment[1].inInventory[0] = equipment[1].level.map((x)=> inventoryItemList.findIndex(y => y[1] == equipment[1].name[equipment[1].level.indexOf(x)] && y[0] == equipment[1].level[equipment[1].level.indexOf(x)])); equipment[1].inInventory[0] = equipment[1].inInventory[0].map((x)=> {if(x ==-1){ return false}else{ return true} }); i = 2; equipment[2].level = heroStatus.map((x) => x[2+(2*i)]); equipment[2].name = heroStatus.map((x) => x[3+(2*i)]); equipment[2].levelNum = equipment[2].level.map((x) => equipmentLevelNames.findIndex((y)=> y==x )); equipment[2].equipped = heroEquippedItems.map((x) => x[i]); equipment[2].inInventory[0] = equipment[2].level.map((x)=> inventoryItemList.findIndex(y => y[1] == equipment[2].name[equipment[2].level.indexOf(x)] && y[0] == equipment[2].level[equipment[2].level.indexOf(x)])); equipment[2].inInventory[0] = equipment[2].inInventory[0].map((x)=> {if(x ==-1){ return false}else{ return true} });
- 嵌套对象结构截图:显示equipment数组的6个元素均指向同一个equipmentType对象的内存地址
- 执行到i=1前的状态截图:equipment[0]完成赋值后,数组内所有元素的属性都同步更新为相同内容
问题原因
核心是引用类型的共享指向:创建equipment数组时,Array.from(Array(6), () => equipmentType )的回调函数每次都返回同一个equipmentType对象的引用。由于对象属于引用类型,数组中的所有元素本质上都是指向同一个对象的指针,修改任何一个元素的属性,都会直接修改底层的同一个对象,导致所有元素同步变化。
修复方案
需要为数组的每个元素生成独立的对象实例,避免复用同一引用,以下是两种实现方式:
方式1:使用工厂函数生成新对象
// 定义工厂函数,每次调用都返回全新的对象实例 function createEquipmentType() { const level = Array(heroStatus.length); const name = Array(heroStatus.length); const levelnum = Array(heroStatus.length); const equipped = Array(heroStatus.length); const inInventory = Array.from(Array(5), () => new Array(heroStatus.length)); return { level, name, levelnum, equipped, inInventory }; } // 生成equipment数组,每个元素都是独立对象 let equipment = Array.from(Array(6), () => createEquipmentType());
方式2:在Array.from回调中直接创建新对象
let equipment = Array.from(Array(6), () => { const level = Array(heroStatus.length); const name = Array(heroStatus.length); const levelnum = Array(heroStatus.length); const equipped = Array(heroStatus.length); const inInventory = Array.from(Array(5), () => new Array(heroStatus.length)); return { level, name, levelnum, equipped, inInventory }; });
额外优化:简化重复赋值逻辑
原代码中重复的赋值块可以用循环简化,同时修复level.indexOf(x)在level有重复值时的错误:
for (let i = 0; i < 3; i++) { equipment[i].level = heroStatus.map(x => x[2 + (2 * i)]); equipment[i].name = heroStatus.map(x => x[3 + (2 * i)]); equipment[i].levelNum = equipment[i].level.map(x => equipmentLevelNames.findIndex(y => y === x)); equipment[i].equipped = heroEquippedItems.map(x => x[i]); // 直接通过索引获取对应name,避免重复调用indexOf导致的错误 equipment[i].inInventory[0] = equipment[i].level.map((levelVal, idx) => { const nameVal = equipment[i].name[idx]; const foundIndex = inventoryItemList.findIndex(y => y[1] === nameVal && y[0] === levelVal); return foundIndex !== -1; }); }
内容的提问来源于stack exchange,提问作者oyvindyr
相关产品推荐
相关产品推荐

