JavaScript:从对象数组中筛选无重复键的对象(保留每个键的最后实例)
问题分析与修复方案
咱先拆解你遇到的问题:你的代码只输出[ { id: 1 } ],核心有两个bug,而且逻辑方向也不符合需求——你要的是保留最后出现的同键对象,但原代码是按从左到右筛选,还写错了键的引用方式。
原代码的两个致命问题
- 错误的键引用:你已经用
let key = Object.keys(element)[0];拿到了当前对象的唯一键,但后面判断重复时用了element.key——这完全是错的!element是你遍历的对象,它根本没有key这个属性,所以element.key的值永远是undefined。第一次循环时,uniqueIds里没有undefined,所以把undefined加进去,后面所有循环都会判断uniqueIds.includes(undefined)为true,自然只保留第一个元素。 - 逻辑方向错误:
filter是从数组头部开始遍历,会保留第一次出现的键对应的对象,但你的需求是保留最后一次出现的,这个思路从根上就不符合要求。
方案1:简洁实现(不严格要求顺序)
如果对结果数组的顺序没有严格要求(只要每个键保留最后出现的实例即可),用对象存储是最简洁的方式:遍历数组时,用当前对象覆盖同键的旧值,最后把对象的值转成数组就行。
let obj = [ { id : 1 }, { id : 10 }, { brand : 12 }, { id : 15 }, { id : 18 }, { image_link : 'some link' }, { price : 10 }, { brand : 111 }, { image_link : 'some link 2' } ]; const tempObj = {}; obj.forEach(item => { const key = Object.keys(item)[0]; tempObj[key] = item; // 每次遇到同键就覆盖,最后留下的肯定是最后出现的实例 }); const unique = Object.values(tempObj); console.log(unique); // 输出:[ { id: 18 }, { brand: 111 }, { image_link: 'some link 2' }, { price: 10 } ]
方案2:严格保持最后出现的顺序
如果需要结果数组的顺序和原数组中各键最后出现的位置顺序一致(比如原数组中id最后出现在第4位,price在第6位,brand在第7位,image_link在第8位,所以结果顺序是id → price → brand → image_link),可以倒序遍历数组,用Set记录已处理的键,遇到未处理的就加到数组开头:
let obj = [ { id : 1 }, { id : 10 }, { brand : 12 }, { id : 15 }, { id : 18 }, { image_link : 'some link' }, { price : 10 }, { brand : 111 }, { image_link : 'some link 2' } ]; const seenKeys = new Set(); const unique = []; // 从数组末尾往前遍历 for (let i = obj.length - 1; i >= 0; i--) { const currentItem = obj[i]; const key = Object.keys(currentItem)[0]; if (!seenKeys.has(key)) { seenKeys.add(key); unique.unshift(currentItem); // 加到数组开头,保证顺序和原数组最后出现的顺序一致 } } console.log(unique); // 输出:[ { id: 18 }, { price: 10 }, { brand: 111 }, { image_link: 'some link 2' } ]
内容的提问来源于stack exchange,提问作者Shibbir
相关产品推荐
相关产品推荐

