金色小芝麻

vuePress-theme-reco 金色小芝麻    2021 - 2023
金色小芝麻 金色小芝麻

Choose mode

  • dark
  • auto
  • light
主页
分类
  • JavaScript
  • BUG复盘
  • SVG笔记
  • TypeScript
  • 个人总结
  • CSS笔记
  • 开发工具
  • 前端入门
  • Vue2.0
  • 性能优化
  • 架构学习
  • 每日一题
标签
时间轴
社交
  • 掘金 (opens new window)
author-avatar

金色小芝麻

83

文章

27

标签

主页
分类
  • JavaScript
  • BUG复盘
  • SVG笔记
  • TypeScript
  • 个人总结
  • CSS笔记
  • 开发工具
  • 前端入门
  • Vue2.0
  • 性能优化
  • 架构学习
  • 每日一题
标签
时间轴
社交
  • 掘金 (opens new window)
  • 前端入门

    • 博客搭建过程及相关配置
    • 数组中的16种常用方法
    • JS中的数据类型简析——基本数据类型值
    • JS中的数据类型object基础
    • JS中三种常见的判断
    • 数据类型之间的区别(堆内存Heap VS 栈内存Stack)
    • JS基础练习题及解析
    • 开关灯的小案例
    • JS中数据类型检测方法——typeof
    • 条件判断几个小练习
    • JS循环——for循环
    • 自定义属性实现选项卡小案例
    • 字符串中的12种常用方法
    • DOM操作的简单原理
    • JS实现隔行变色鼠标跟随小案例
    • JS中function的基础知识
    • JS中数组去重的三种方法
    • JS中时间格式化的三种方法
    • JS中URL参数处理的三种方法
    • JS小案例——获取随机验证码
    • DOM操作之——获取DOM标签的9种方式
    • DOM操作之——DOM节点类型及属性
    • DOM操作之——元素的增删改、样式修改、插入内容
    • JS中THIS相关问题梳理
    • JS中的变量提升机制
    • 在全局:私有上下文中:带VAR和不带VAR的区别
    • 作用域和作用域链查找机制
    • JS中堆栈内存的释放问题
    • JS中的闭包机制
    • ES3和ES6定义变量的区别
    • JS中的单例和工厂设计模式
    • JS中的面向对象OOP理论基础
    • 构造函数创建自定义类
    • JS中的原型和原型链
    • Math中常用的9种方法
    • 从一道阿里经典面试题剖析函数三种角色
    • 重写内置call
    • 重写一个内置new
    • 浏览器渲染页面的主体流程
    • 减少DOM的回流和重绘
    • JS中的多种继承方式
    • JS中数据类型检测四种方式的优缺点
    • JS中的正则表达式&&全面梳理
    • 非严格模式 🆚 严格模式的区别
    • 数组方法reduce、filter、flat
    • 获取数组中最大值/最小值的三种基础方法
    • 轮播图——渐隐渐显版
    • 深克隆 VS 浅克隆|深比较 VS 浅比较|回调函数
    • 轮播图——左右切换版
    • 事件及事件绑定、事件对象及事件传播
    • 从在地址栏输入网址到看到页面的过程&&AJAX基础
    • 想自学JS吗?想提升JS底层原理吗?76张脑图带你彻底搞懂原生JS
    • 面试手写API系列
    • 30张脑图带你从零开始学VUE
    • JS中的盒子模型
    • 初识JS-基础中的基础
    • 前端发展简史
    • JS中的三大类输出方式

JS中数组去重的三种方法

vuePress-theme-reco 金色小芝麻    2021 - 2023

JS中数组去重的三种方法

金色小芝麻 2020-04-18

数组去重的方式有很多种,我们先拿出3种比较简单的进行学习;

  • 1.双FOR循环(拿当前项和后面的每一项进行比较,重点:数组塌陷和SPLICE删除的优化)
  • 2.对象的键值对方式
  • 3.indxOf检测的方式

# 思维导图

# 一、双FOR循环方式

原理:依次遍历数组中的每一项,拿当前项和其“后面”的每一项进行比较,如果后面中有和他相同的,则说明这项是重复的,我们把后面中重复的这一项删除掉即可

let arr = [1, 1, 1, 2, 2, 3, 2, 2, 1, 2, 3, 2, 1, 2, 2, 3];
//====外层循环控制每一次拿出一项和其后面的比
//  i < arr.length - 1 最后一项不需要再拿出来了,因为每一次都是和当前项后面的比较,而最后一项后面没有任何的东西,所以也就没有必要再拿出来比较了
for (let i = 0; i < arr.length - 1; i++) {
    // 每一次拿出来要和后面依次比较的那一项
    let item = arr[i];
    //====里层循环控制和当前项后面的每一项逐一比较
    // let j = i + 1 从当前项的后一项开始逐一比较即可
    for (let j = i + 1; j < arr.length; j++) {
        if (item === arr[j]) {
        // 当前项和后面中的某一项相等了,此时我们把后面中的这一项从原始数组中删除掉
        arr.splice(j, 1);
    
        j--; //=>删除完,先让j--,然后在j++,相当于没加没减,下一轮还是从当前索引开始比较,这样防止数组塌陷带来的问题
        }
    }
}

# 1、用splice删除需注意的两点:

  • 第一点:数组塌陷问题:以用--解决

解决完splice引起的塌陷问题后我们已经可以实现想要的效果,但是根据上图我们可以知道,

  • 在删除重复项后后面每一项的索引都会向前提一位,这样(如果删除的这一项后面还有1000万项,那么这1000万项的索引都要向前提一位)会大大的消耗性能,
  • 所以我们需要做进一步的优化处理;
  • 第二点:性能优化

# 2、优化后的代码如下:

for (let i = 0; i < arr.length - 1; i++) {
    let item = arr[i];
    for (let j = i + 1; j < arr.length; j++) {
        if (item === arr[j]) {
            // 用最后一项替换当前项
            arr[j] = arr[arr.length - 1];// 原始数组中的顺序会变化,但是不会导致索引前置这种情况(性能好)
            // 最后一项删掉
            arr.length--;
            // 下一轮还和这一项比(因为这一项已经变为最新的最后一项了)
            j--;
        }
    }
}
console.log(arr);

# 二、对象键值对的方式

原理:利用对象中属性名不能重复的特点,先建立一个空对象,然后依次循环数组中的每一项,把此项作为obj对象的属性名和属性值,在添加的时候,如果这个属性名对应的值已经存在,说明此项重复,删除掉此项

let arr = [1, 2, 3, 1, 1, 4, 2, 3];
let obj = {};
for (let i = 0; i < arr.length; i++) {
    // 把每一次循环得到的当前项,作为对象的属性名和属性值存储进去
    let item = arr[i];
    if (obj[item] !== undefined) {
        // 证明对象中有这个属性(也就是之前存储过,数组中之前就有这个值),当前值是重复的,我们需要把当前这项的值删掉即可
        arr[i] = arr[arr.length - 1];
        arr.length--;
        i--;
        continue;
    }
    obj[item] = item;
}
console.log(arr);

# 对象键值对的方式的优缺点

  • 优点:
    • 只有一个循环,所以性能很好
  • 缺点:
    • 1.如果数组中出现对象则存在问题(因为对象的属性名不能是对象,遇到会转换为字符串);
    • 2.如果数组中存在数字10和字符串'10',则也会认为是重复的(对象中的属性名是数字和字符串没啥区别);
    • 3.数组中的值如果是undefined可能也会出现问题....

# 三、indxOf检测的方式

原理:创建一个新数组,遍历原数组,如果新数组中没有那一项的话,就把它push进去

let arr=[1,2,1,3,3,2,3];
let newAry=[];
  /*把原数组中的每一项,只要在新数组中没存在过,我们就把它放进去,最后newAry就是咱们最终要的数组*/
  
for(let i=0;i<arr.length;i++){
       let item=arr[i];
       if(newAry.indexOf(item)==-1){
        newAry.push(item);
       }
   }
arr = newAry;
console.log(arr);

# 缺点:indexOf低版本浏览器不兼容

# 四、ES6利用Set方式

/* ES6中没有提供现成的去重办法,但是提供了一些去重的方式 :Set数据结构*/
let obj = { y: 200 };
let arr = [obj, 1, 2, 3, 1, obj, 1, 4, 2, 3, '3', { x: 100 }, { x: 100 }];
arr = Array.from(new Set(arr));
console.log(arr);

# 缺点:低版本浏览器不兼容

欢迎来到 金色小芝麻
看板娘