
本文介绍如何遍历对象数组,为重复 productname 的条目赋予其首次出现时对应的 productid,从而实现语义一致的去重标识,适用于商品归一化、数据清洗等场景。
本文介绍如何遍历对象数组,为重复 productname 的条目赋予其首次出现时对应的 productid,从而实现语义一致的去重标识,适用于商品归一化、数据清洗等场景。
在实际前端开发或数据处理中,常遇到“名称相同但 ID 不同”的对象数组(如商品列表),而业务逻辑要求将语义相同的项视为同一实体——即所有同名商品应共享首个出现时的 productId。这并非简单去重,而是保留原始结构与数量,仅修正重复项的 ID 字段。
实现思路是:一次遍历 + 哈希映射(Map)记录首次出现的 productId。对每个对象,若其 productName 已存在于映射表中,则将其 productId 更新为首次记录的值;否则,将当前 productId 缓存到映射表中。
以下是完整、健壮的实现代码:
const products = [
{ productId: 1, productName: 'Apple', price: 1.0 },
{ productId: 2, productName: 'Banana', price: 0.5 },
{ productId: 3, productName: 'Orange', price: 1.2 },
{ productId: 4, productName: 'Apple', price: 1.0 },
{ productId: 5, productName: 'Banana', price: 0.5 },
];
// 创建 productName → first productId 映射
const nameToFirstId = new Map();
products.forEach((product, index) => {
if (nameToFirstId.has(product.productName)) {
// 若已存在,覆盖当前 productId 为首次 ID
product.productId = nameToFirstId.get(product.productName);
} else {
// 首次出现,缓存其 productId
nameToFirstId.set(product.productName, product.productId);
}
});
console.log(products);
// 输出符合预期:
// [
// { productId: 1, productName: 'Apple', price: 1.0 },
// { productId: 2, productName: 'Banana', price: 0.5 },
// { productId: 3, productName: 'Orange', price: 1.2 },
// { productId: 1, productName: 'Apple', price: 1.0 },
// { productId: 2, productName: 'Banana', price: 0.5 }
// ]✅ 关键优势:
- 时间复杂度 O(n),空间复杂度 O(k)(k 为唯一 productName 数量);
- 使用
Map替代普通对象,避免原型污染与类型转换风险(如productName: 'constructor'); - 直接原地修改,不创建新数组,节省内存(如需不可变操作,可先深拷贝再处理)。
⚠️ 注意事项:
- 此方案假设
productName是唯一语义标识字段;若需多字段联合判断(如productName + price),请扩展键生成逻辑(例如const key =${p.productName}|${p.price}``); - 原始数组被修改,如需保持输入不变,请先执行
products.map(p => ({ ...p }))创建浅拷贝(注意嵌套对象需深拷贝); -
productId字段名大小写需与原始数据严格一致(示例中为productId,非productid)。
总结:该模式简洁高效,是处理“命名归一化”类问题的标准实践,既满足业务语义一致性,又兼顾性能与可维护性。

















