JavaScript 数组去重

81 阅读2分钟

以下是 JavaScript 数组去重的常用方法及详细说明(按技术栈由新到旧排序):


⭐️ 推荐方案(ES6+)

1. 使用 Set 数据结构

const arr = [1, 2, 2, '2', NaN, NaN, {a:1}, {a:1}];
const unique = [...new Set(arr)];
// 结果:[1, 2, '2', NaN, {a:1}, {a:1}]

特点:

  • 自动处理 NaN 去重(Set 认为 NaN === NaN)
  • 无法处理对象类型去重(对象引用不同)
  • 最高效的方式,时间复杂度 O(n)

2. 使用 filter + indexOf

const arr = [1, 2, 2, '2', NaN];
const unique = arr.filter((item, index) => arr.indexOf(item) === index);
// 结果:[1, 2, '2'](无法处理 NaN)

特点:

  • indexOf 无法检测 NaN(NaN 总是返回 -1)
  • 无法区分 1 和 '1' 等类型差异

3. 使用 reduce 实现

const arr = [1, 2, 2, '2', NaN, NaN];
const unique = arr.reduce((acc, cur) => {
  return acc.includes(cur) ? acc : [...acc, cur];
}, []);
// 结果:[1, 2, '2', NaN]

特点:

  • 可处理 NaN(includes 能检测 NaN)
  • 保留首次出现顺序

传统方案(ES5)

4. 对象键值法

function unique(arr) {
  const obj = {};
  return arr.filter(item => {
    const key = typeof item + JSON.stringify(item);
    return obj.hasOwnProperty(key) ? false : (obj[key] = true);
  });
}

const arr = [1, 2, '2', NaN, NaN, {a:1}, {a:1}];
unique(arr); 
// 结果:[1, 2, '2', NaN, {a:1}]

特点:

  • 处理复杂类型(通过序列化存储)
  • 性能较好,但需要注意 JSON.stringify 的局限性

5. 双重循环(基础实现)

function unique(arr) {
  const res = [];
  for (let i = 0; i < arr.length; i++) {
    let isDuplicate = false;
    for (let j = 0; j < res.length; j++) {
      if (arr[i] === res[j]) {
        isDuplicate = true;
        break;
      }
    }
    if (!isDuplicate) res.push(arr[i]);
  }
  return res;
}

特点:

  • 最基础的实现方式
  • 时间复杂度 O(n²),性能最差

特殊场景处理

对象数组去重

const arr = [{id:1}, {id:1}, {id:2}];
const unique = [...new Map(arr.map(item => [item.id, item])).values()];
// 结果:[{id:1}, {id:2}]

方法对比

方法处理 NaN处理对象时间复杂度保持顺序
SetO(n)
filter + indexOfO(n²)
reduce + includesO(n²)
对象键值法O(n)
双重循环O(n²)

推荐选择原则

  1. 现代项目首选 Set 方案
  2. 需要处理复杂对象时使用 对象键值法
  3. 需要兼容旧浏览器时使用 filter + indexOf
  4. 特殊需求场景使用自定义方法

注意:所有方法都要根据具体数据类型选择,没有绝对通用的完美方案。