
本文介绍如何正确提取数组中所有重复出现的元素,且每个重复值仅保留一次,避免多次输出同一重复项。
在 JavaScript 中,若需从一个数组中提取“所有重复出现过的值”,但要求结果数组中每个重复值仅出现一次(如 [1, 2, 3, 1, 5, 6, 1, 2, 5] 应返回 [1, 2, 5]),直接使用 filter() 配合 indexOf() 会导致重复项被多次捕获——因为 array.indexOf(item) !== index 对于第二个及之后的相同元素均成立(例如 1 在索引 3 和 6 处都会满足条件),从而输出 [1, 1, 2, 5]。
要实现「去重后的重复项」,核心思路是:先识别哪些元素出现了 ≥2 次,再确保结果中每个这样的元素只出现一次。以下是几种推荐的现代、可读性强且高效的实现方式:
✅ 方法一:使用 Set + filter + indexOf/lastIndexOf(简洁推荐)
const array = [1, 2, 3, 1, 5, 6, 1, 2, 5]; const duplicates = [...new Set( array.filter(item => array.indexOf(item) !== array.lastIndexOf(item)) )]; console.log(duplicates); // [1, 2, 5]
✅ 原理:indexOf(item) !== lastIndexOf(item) 表示该元素至少出现两次;外层 new Set() 自动去重,保证每个重复值只保留一次。
✅ 方法二:使用 Map 统计频次(扩展性强,适合复杂场景)
const array = [1, 2, 3, 1, 5, 6, 1, 2, 5];
const countMap = new Map();
array.forEach(item => {
countMap.set(item, (countMap.get(item) || 0) + 1);
});
const duplicates = [...countMap.entries()]
.filter(([_, count]) => count > 1)
.map(([item]) => item);
console.log(duplicates); // [1, 2, 5]✅ 优势:逻辑清晰、易于调试,且便于后续扩展(如筛选出现 ≥3 次的元素)。
⚠️ 注意事项
- ❌ 避免仅用 filter + indexOf(item) !== index:它会返回所有非首次出现的元素,而非「重复元素的集合」。
- ✅ Set 是去重最安全的方式,尤其比手动遍历 indexOf 更高效、不易出错。
- ? 若数组含对象或嵌套结构,需改用深比较逻辑(本文默认处理原始值:number/string/boolean)。
- ? 推荐在生产环境使用方法一(简洁)或方法二(可维护),避免原问题中基于 for...in 的老旧写法(for...in 不适用于数组,易遍历原型链属性)。
总结
获取「唯一重复元素」的关键在于两步分离:检测重复性 → 去重结果。优先选用语义明确、性能可靠、符合现代 JS 规范的写法,既提升代码可读性,也避免隐式 bug。










