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

数组对象赋值时所有元素同步修改的问题及修复方案

对象数组元素同步修改问题的修复方案

问题描述

我有一个包含数组的嵌套对象,同时存在该对象的数组。当尝试访问并修改该对象数组的第一个元素时,发现数组中所有元素都被同步修改。原代码使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 19:17:04