JavaScript 数组去重全解:6 种核心方法

目录

  • 核心基础知识点
  • [6 种数组去重方法详解](#6 种数组去重方法详解)
    • [方法 1:双重循环去重(基础实现)](#方法 1:双重循环去重(基础实现))
    • [方法 2:indexOf 单循环去重](#方法 2:indexOf 单循环去重)
    • [方法 3:filter + indexOf 去重](#方法 3:filter + indexOf 去重)
    • [方法 4:排序 + 相邻对比去重](#方法 4:排序 + 相邻对比去重)
    • [方法 5:对象字面量去重(空间换时间)](#方法 5:对象字面量去重(空间换时间))
    • [方法 6:ES6 Set 去重(最优简洁版)](#方法 6:ES6 Set 去重(最优简洁版))
  • 方法对比
  • 总结

核心基础知识点

题目场景

  • 需求:对数组 1,2,3,2,5,5,6,3 实现去重,得到无重复元素的新数组

代码规范与设计原则

  1. 注释规范
    注释是代码的核心组成部分,提升可读性,方便团队协作、个人回顾代码
  2. 单一职责
    一个函数只实现一个核心功能(数组去重)。
  3. 封装思想
    将复杂的去重逻辑封装为独立函数,复用性更强。
  4. 健壮性要求
    必须做参数校验,避免非数组参数导致程序报错。

必备数组 API

API 作用
Array.isArray(arr) 判断数据是否为数组(参数校验核心方法),是返回true,不是返回false
arr.indexOf(item) 查询元素在数组中第一次出现的下标,不存在返回 -1
arr.filter(callback) 数组过滤,根据回调返回值保留 / 剔除元素
arr.sort() 数组排序,为相邻去重做准备

复杂度

时间复杂度:

O(n²):双重for计数循环、filter+indexOf(效率较低)

O(nlogn):先排序再去重(中等效率)

O(n):对象 / Set 去重(最优效率,但是最消耗空间)

空间换时间:用额外对象 / Set 存储数据,提升执行速度

6 种数组去重方法详解

方法 1:双重循环去重(基础实现)

核心思路

定义结果数组,外层遍历原数组,内层遍历结果数组,通过标记判断元素是否重复,无重复则加入结果数组。

javascript 复制代码
function unique(arr){
    // 参数校验:非数组返回空数组
    if(!Array.isArray(arr)){
        console.log('type error');
        return [];
    }
    // 初始化结果数组,放入第一个元素
    let res=[arr[0]];
    // 外层循环:从第二个元素开始遍历原数组
    for(let i=1;i<arr.length;i++){
        let flag=true; // 标记:默认当前元素不重复
        // 内层循环:遍历结果数组,对比是否重复
        for(let j=0;j<res.length;j++){
            if(arr[i] === res[j]){
                flag=false; // 发现重复,修改标记
                break; // 终止内层循环
            }
        }
        // 无重复则添加到结果数组
        if(flag){
            res.push(arr[i]);
        }
    }
    return res;
}
console.log(unique([1,2,3,2,5])); // [1,2,3,5]

复杂度:O(n²)


方法 2:indexOf 单循环去重

核心思路

利用 indexOf 判断元素是否已存在于结果数组,不存在则添加,简化内层循环。

javascript 复制代码
function unique(arr){
    // 参数校验
    if(!Array.isArray(arr)){
        console.log('type error');
        return [];
    }
    const res=[];
    // 遍历原数组
    for(let i=0;i<arr.length;i++){
        // indexOf返回-1:元素不存在于结果数组
        if(res.indexOf(arr[i])===-1){
            res.push(arr[i]);
        }
    }
    return res;
}

复杂度 :O(n²)

优点:比双重循环代码更简洁


方法 3:filter + indexOf 去重

核心思路

利用 filter 过滤数组,保留第一次出现的元素 :indexOf 返回元素首次出现的下标,与当前下标一致则保留

javascript 复制代码
function unique(arr){
    // 参数校验
    if(!Array.isArray(arr)){
        console.log('type error');
        return [];
    }
    // filter:返回符合条件的新数组
    return arr.filter(function(item,index){
        // 仅保留元素第一次出现的位置
        return arr.indexOf(item)===index;
    })
}

复杂度:O(n²)

优点:代码极简,一行实现核心逻辑


方法 4:排序 + 相邻对比去重

核心思路

先对数组排序 ,重复元素会变为相邻元素,遍历数组,仅保留与前一个元素不同的值

javascript 复制代码
function unique(arr){
    // 参数校验
    if(!Array.isArray(arr)){
        console.log('type error');
        return [];
    }
    arr.sort(); // 数组排序
    let res=[arr[0]];
    // 遍历数组,对比相邻元素
    for(let i=1;i<arr.length;i++){
        if(arr[i]!==arr[i-1]){
            res.push(arr[i]);
        }
    }
    return res;
}

复杂度:O(nlogn)

注意:排序会改变原数组元素的顺序


方法 5:对象字面量去重(空间换时间)

核心思路

对象中的key表示值,value 表示它是否出现

用对象存储已出现的元素,遍历数组时,通过对象 key 判断是否重复,仅遍历一次数组,效率极高

javascript 复制代码
function unique(arr){
    // 参数校验
    if(!Array.isArray(arr)){
        console.log('type error');
        return [];
    }
    let res=[];
    let obj={}; // 对象:key存储数组元素,value标记是否存在
    for(let i=0;i<arr.length;i++){
        // 对象中无该key:表示未重复
        if(!obj[arr[i]]){
            res.push(arr[i]);
            obj[arr[i]]=1; // 标记为已存在
        }
    }
    return res;
}

复杂度:O(n)

优点:执行速度最快,大数据量优先使用


方法 6:ES6 Set 去重(最优简洁版)

核心思路

Set 是 ES6 提供的不重复数据容器,直接将数组转为 Set 去重,再展开为新数组。

javascript 复制代码
function unique(arr){
    // 参数校验
    if(!Array.isArray(arr)){
        console.log('type error');
        return [];
    }
    // 数组转Set去重 → 展开运算符转回数组
    return [...new Set(arr)];
}

复杂度:O(n)

优点:代码最简洁、性能最优、企业开发首选

方法对比

方法 复杂度 代码量 适用场景
双重循环 O(n²) 学习基础逻辑
indexOf 循环 O(n²) 中等 简单业务场景
filter+indexOf O(n²) 极简 代码简洁优先
排序 + 相邻 O(nlogn) 中等 允许改变元素顺序
对象去重 O(n) 中等 大数据量、高性能要求
ES6 Set O(n) 极简 现代浏览器 / 项目首选

总结

数组去重是前端必备基础能力,核心是判断元素是否重复;

所有方案都必须包含参数校验,保证代码健壮性;

复杂度从低到高:O(n) < O(nlogn) < O(n²);

最优方案:ES6 Set 去重,兼顾简洁性与性能;

核心思想:循环对比、API 复用、空间换时间。

相关推荐
冬奇Lab1 小时前
AI Workflow 定义的四次演进:从 Markdown 到 JS 脚本,再到分布式多 Agent
javascript·人工智能·agent
一颗烂土豆7 小时前
Meshopt 压缩深度解析,为什么它比 Draco 更快
前端·javascript·webgl
kyriewen9 小时前
同事每天催我 Code Review,我写了个脚本让 AI 替我 review PR——现在他反过来催 AI 了
前端·javascript·ai编程
weedsfly12 小时前
迭代器、生成器与异步迭代——让数据“按需流动”的艺术
前端·javascript
假如让我当三天老蒯12 小时前
前端跨域解决方案(学习用)
前端·javascript·面试
铁皮饭盒14 小时前
Bun 哪比 Node.js 快?
javascript·后端
JieE2121 天前
LeetCode 56. 合并区间|超清晰 JS 图解思路,面试高频区间题
javascript·算法·面试
candyTong1 天前
RTK 技术原理:一次典型会话里,80% 上下文是怎么省下来的
javascript·后端·架构
_柳青杨1 天前
深入理解 JavaScript 事件循环
前端·javascript
大家的林语冰1 天前
ES5 凉凉,Babel 8 正式发布,默认不再编译为 ES5 和 CJS......
前端·javascript·前端工程化