NodeJS中嵌套对象内数组实例全部重复的问题排查
我有一个嵌套对象数组,每个对象内部包含一个lines数组,简化结构如下:
const nestedArray = [ objectTemp{foo: "", lines: []} ] // 嵌套数组结构的简化示例
我给每个模板对象填充不同的foo值和lines数组内容,然后推入nestedArray。但操作后发现,nestedArray中每个对象的lines数组内容完全相同,而foo值则正常保持不同。
实际场景是遍历订单数据orderData,拆分客户与订单数据,combinedData是存储newOrder对象的数组,每个newOrder的lines数组用于存储订单项。循环结束后,每个对象的属性值都正常不同,但所有对象的lines数组内容完全一致。
以下是实际代码:
主循环代码
for(let i = 0; i < orderData.length; i++){ if(lastOrder === orderData[i]["Order Name"]){ // 多订单项的订单 newLine = await fillLineData(orderData[i]); await pushToArray(newOrder.lines, newLine); } else{ // 循环进入下一订单,将newOrder对象存入combinedData数组 if(lastOrder) { await pushToArray(combinedData, newOrder); newOrder = await clearObject(newOrder); } // 开始处理下一订单数据 const extKey = await getCustomerKey(orderData[i]); newOrder = await fillCustomerData(orderData[i], extKey); newLine = await fillLineData(orderData[i]); await pushToArray(newOrder.lines, newLine); } lastOrder = orderData[i]["Order Name"]; } await pushToArray(combinedData, newOrder); // 辅助函数 async function pushToArray(arr, obj){ try{ arr.push(obj); }catch(e){ console.log("Failed to push order lines to array... Error: ", e); } }
fillCustomerData函数代码
async function fillCustomerData(orderData, extKey){ const newData = Object.create(orderCustomerData); newData.customer_name = orderData["Customer Name"]; newData.shipto_name = orderData["Customer Name (Shipping)"]; newData.shipto_address_1 = orderData["Shipping Address 1"]; newData.shipto_address_2 = orderData["Shipping Address 2"]; newData.shipto_city = orderData["Shipping City"]; newData.shipto_state = orderData["Shipping Province Code"]; newData.shipto_zip = orderData["Shipping ZIP"]; newData.shipto_country = orderData["Shipping Country"], newData.billto_name = orderData["Customer Name (Billing)"]; newData.billto_address_1 = orderData["Billing Address 1"]; newData.billto_address_2 = orderData["Billing Address 2"]; newData.billto_city = orderData["Billing City"]; newData.billto_state = orderData["Billing Province Code"]; newData.billto_zip = orderData["Billing ZIP"]; newData.billto_country = orderData["Billing Country"]; newData.po = orderData["Order Name"]; newData.tax_collected = orderData["Total Tax"]; newData.freight_resale = orderData["Shipping Price"]; newData.external_key = extKey; return newData; }
核心原因
你用Object.create(orderCustomerData)创建对象时,orderCustomerData里的lines数组是引用类型,会作为原型属性被所有newData实例共享。也就是说,所有newOrder对象的lines其实指向同一个数组地址,不管你给哪个对象的lines加元素,所有对象的lines都会同步变化,最终内容完全一致。
而foo这类基本类型属性,你在newData上直接赋值时,会在实例自身创建新属性覆盖原型上的同名属性,所以每个对象的foo值能保持独立。
解决方案
1. 修改fillCustomerData函数,给每个实例创建独立lines数组
在创建newData后,新增一行代码给当前实例单独初始化lines数组,切断原型共享:
async function fillCustomerData(orderData, extKey){ const newData = Object.create(orderCustomerData); // 给当前实例创建独立的lines数组 newData.lines = []; newData.customer_name = orderData["Customer Name"]; newData.shipto_name = orderData["Customer Name (Shipping)"]; // ...其他属性赋值代码保持不变 return newData; }
2. 检查clearObject函数的处理逻辑
如果clearObject只是清空原数组(比如用obj.lines.length = 0),会导致后续复用的对象仍然共享同一个数组。确保clearObject是给lines重新赋值新数组:
async function clearObject(obj) { // 清空其他属性... obj.lines = []; // 重置为新数组,而非清空原数组 return obj; }
这样每个newOrder对象都会拥有独立的lines数组,各自的订单项就不会互相干扰了。
内容的提问来源于stack exchange,提问作者NoahDuV

