filter配合indexof去重的原理是:只保留当前元素首次出现位置等于其遍历索引的项;适用于原始类型,但不适用于对象,且时间复杂度为o(n²)。

使用 filter 配合 indexOf 是 JS 中一种简洁、易懂的数组去重方法,核心原理是:**只保留当前元素第一次出现的位置(即 indexOf 返回的索引)等于它当前遍历位置的那些项**。
为什么 filter + indexOf 能去重?
filter(callback) 会遍历数组每一项,并对每个元素执行回调函数;callback 接收三个参数:item(当前元素)、index(当前下标)、arr(原数组)。indexOf(item) 总是返回该元素在数组中**首次出现的索引**。
所以当 index === arr.indexOf(item) 为 true,说明这是该值第一次出现——保留;否则就是重复项——过滤掉。
基础写法(适用于简单类型)
适用于字符串、数字、布尔值等原始类型:
const arr = [1, 2, 2, 3, 4, 4, 5]; const unique = arr.filter((item, index) => index === arr.indexOf(item)); console.log(unique); // [1, 2, 3, 4, 5]
注意事项和常见问题
-
不适用于对象或嵌套结构:因为
indexOf对象比较用的是引用,两个内容相同但不同地址的对象会被视为不相等,且indexOf找不到也会返回-1,导致逻辑错乱。 -
性能不是最优:每次调用
indexOf都要从头遍历,时间复杂度是 O(n²),大数据量时慎用。 -
NaN 的特殊情况:
NaN !== NaN,但[NaN].indexOf(NaN)返回0(ES6 规范已修复),所以此方法对NaN可以正确保留一个,无需额外处理。
替代建议(更推荐的现代写法)
如果追求简洁与兼容性兼顾,可优先考虑:
-
[...new Set(arr)]—— 最简写法,适合大多数原始类型场景 -
arr.reduce((acc, item) => acc.includes(item) ? acc : [...acc, item], [])—— 更可控,但性能略低 - 对象数组去重需配合
findIndex或序列化(如JSON.stringify),不能直接用indexOf











