set配合扩展运算符是javascript数组去重并保持原始顺序的最推荐方法,因其简洁高效、天然保序且能正确处理nan、null、undefined等特殊值;filter+indexof兼容旧环境但性能为o(n²);reduce适合对象数组按字段去重,结合set缓存可实现o(n)高效处理。

JavaScript 数组去重时保持原始顺序,关键在于避免排序、不依赖索引错位,并选用天然保序的机制。现代标准下,Set 配合扩展运算符是最直接可靠的方式,它既不打乱顺序,也不修改原数组,还能正确处理 NaN、null、undefined 等特殊值。
用 Set + 扩展运算符(推荐,简洁高效)
Set 的内部实现按插入顺序存储元素,遍历时也严格遵循该顺序。因此转成数组后,首次出现的元素位置被完整保留。
- 写法:
const unique = [...new Set(arr)]或Array.from(new Set(arr)) - 适用类型:数字、字符串、布尔值、undefined、null、NaN(Set 把 NaN 视为相同值)
- 注意:对对象或数组等引用类型无效,因为两个内容相同的对象仍是不同引用
用 filter + indexOf(兼容旧环境,如 IE)
利用 indexOf 总是返回元素第一次出现的位置这一特性,只保留“当前索引等于首次出现索引”的项。
将一个或多个视频上传至YouTube。当用户想“上传到YouTube”“发YouTube”“批量上传”“upload to YouTube”“post videos to YouTube”或发布到YouTube时使用此技能。
- 写法:
arr.filter((item, index) => arr.indexOf(item) === index) - 优点:不依赖 ES6,逻辑清晰,适合小到中等规模数组
- 缺点:时间复杂度为 O(n²),大数据量时性能明显下降
用 reduce 自定义去重逻辑(适合对象数组或复杂判断)
当需要按某个字段(如 id)去重,或需结合条件判断时,reduce 提供了最大灵活性。
- 基础示例(基本类型):
arr.reduce((acc, cur) => acc.includes(cur) ? acc : [...acc, cur], []) - 对象数组示例(按 id 去重):
users.reduce((acc, user) => acc.some(u => u.id === user.id) ? acc : [...acc, user], []) - 更高效写法建议搭配 Set 缓存已见 id,避免每次
some全遍历
对象数组按属性去重(常见业务场景)
普通方法无法识别两个结构相同但内存地址不同的对象。必须提取唯一标识(如 id、sku)作为判断依据。
- 推荐组合:
filter+Set缓存键值 - 示例:
const seen = new Set(); users.filter(user => !seen.has(user.id) && seen.add(user.id)) - 优势:O(n) 时间复杂度,代码简短,语义明确










