JS数组去重!!!一篇不怎么靠谱的"深度"水文

简介: 数组去重,这是一个老梗了...今天我又拿出来说了... 我们在考虑全面一点的情况下,数组去重的实现,比如针对NaN,undefined,{}; 这其中涉及的知识点挺多,不信跟着走一波; 这里不考虑浏览器兼容性这些破问题,因为涉及ES5&6


前言


数组去重,这是一个老梗了...今天我又拿出来说了... 我们在考虑全面一点的情况下,数组去重的实现,比如针对NaN,undefined,{}; 这其中涉及的知识点挺多,不信跟着走一波; 这里不考虑浏览器兼容性这些破问题,因为涉及ES5&6


实现大全


基础版


只包含一些可以直接比较的数值


测试数组


[1,1,'','','e','e',true,'true',true,false,false,'false',undefined,'undefined',undefined,null,'null',null]


  • ES5万能的for方法


function uniqueUseFor(array) {
  var temp = []; //一个临时数组
  //遍历当前数组
  for (var i = 0, j = array.length; i < j; i++) {
    //很直白,新数组内判断是否有这个值,没有的情况下,就推入该新数组
    temp.indexOf(array[i]) === -1 ? temp.push(array[i]) : '';
  }
  return temp;
}
// result: [1, "", "e", true, "true", false, "false", undefined, "undefined", "null", null]


  • ES5内置的forEach方法


function uniqueUseForEach(array) {
  // 传入值必须存在,且长度小于等于1的时候直接返回数组
  if (array && array.length <= 1) {
    return array;
  } else {
    var temp = []; //一个临时数组
    //遍历当前数组
    array.forEach(function (value, index) {
      temp.indexOf(value) == -1 ? temp.push(value) : '';
    })
    return temp;
  }
}
// result: [1, "", "e", true, "true", false, "false", undefined, "undefined", "null", null]


  • [ES6]内置的for-of方法


function uniqueUseForOf(array) {
  const temp = []; //一个临时数组
  // 传入值必须存在,且长度小于等于1的时候直接返回数组
  if (array && array.length <= 1) {
    return array;
  } else {
    //遍历当前数组
    for (let x of array) {
      temp.indexOf(x) === -1 ? temp.push(x) : '';
    }
  }
  return temp;
}
// result: [1, "", "e", true, "true", false, "false", undefined, "undefined", "null", null]


进阶版


包含NaN,undefined,null


测试数组


[1,1,'true',true,true,5,'F',false, undefined, null,null,undefined, NaN, 0, 1, 'a', 'a', NaN,'NaN']


知识点


  • NaN有两中通用判定方法和数组中一种判定方法:
  • 一个是绝对不全等于(===)自身
  • 一个是ES6isNaN()
  • 数组原型链上的Array.prototype.includes()


function uniqueUseNotAllEqual(array) {
  var temp = [], //一个临时数组
      mark = true; // 标识位
  //遍历当前数组
  for (var i = 0, j = array.length; i < j; i++) {
    // 标识位的作用就是用来判断是否存在NaN,第一次找到保留到新数组中
    // 然后标识位置改为false是为了再次找到的时候不推入数组
    if (array[i] !== array[i]) {
      // 这里的不等特性,也可以用isNaN判断[ES6]
      mark && temp.indexOf(array[i]) == -1 ? temp.push(array[i]) : '';
      mark = false;
    } else
      temp.indexOf(array[i]) == -1 ? temp.push(array[i]) : '';
  }
  return temp;
}
// result: [1, "true", true, 5, "F", false, undefined, null, NaN, 0, "a", "NaN"]


  • [ES6]内置Array.prototype.includes()大法


function uniqueCompareUseIncludes(array) {
  // 传入值必须存在,且长度小于等于1的时候直接返回数组
  if (array && array.length <= 1) {
    return array;
  } else {
    let temp = []; //一个临时数组
    //遍历当前数组
    for (let x of array) {
      // includes() 方法用来判断当前数组是否包含某指定的值,如果是,则返回 true,否则返回 false。
      temp.includes(x) ? '': temp.push(x) ;
    }
    return temp;
  }
}
// result: [1, "true", true, 5, "F", false, undefined, null, NaN, 0, "a", "NaN"]


  • [ES6] Array.from或拓展运算符[...]结合Set大法


知识点


  • Set的值具有唯一性,内部会自动===比较,是可迭代对象(iterable),有点特殊的是NaN这货虽然有不全等的特性,在Set里面认为是相同的,所以只能有一个
  • Array.from...可以把类似数组【nodelist or arguments】这类可迭代的对象中转为一个标准的数组


// Array.from + Set的方法
Array.from(new Set([1,1,'true',true,true,5,'F',false, undefined, null,null,undefined, NaN, 0, 1, 'a', 'a', NaN,'NaN']))
// resule: [1, "true", true, 5, "F", false, undefined, null, NaN, 0, "a", "NaN"]
// ... + Set的方法
[...new Set([1,1,'true',true,true,5,'F',false, undefined, null,null,undefined, NaN, 0, 1, 'a', 'a', NaN,'NaN'])]
//result: [1, "true", true, 5, "F", false, undefined, null, NaN, 0, "a", "NaN"]


高阶版


包含{},NaN,undefined,null


测试数组


[1,1,'true',true,true,5,'F',false, undefined, null,null,undefined, NaN,{},{},'{}', 0, 1, 'a', 'a', NaN]


知识点


  • {}的比较真心不好做,有残缺性的比较可以这样写 JSON.stringify({}) == '{}'
  • 一个比较完美的方案是借助for in结合原型链的toString来判断
  • ES5for-in + call + for方案


function uniqueUseForIn(array) {
  var temp = [];
  var emptyObjectMark = true; // 标识位
  var NaNObjectMark = true; // 标识位
  // 判断空对象,这块判断折腾了许久
  function isEmptyObject(object) {
    if (Object.prototype.toString.call(object) === "[object Object]") {
      for (var i in object) {
        // 存在属性或方法,则不是空对象
        return false
      }
      return true;
    } else {
      return false;
    }
  }
  // 传入值必须存在,且长度小于等于1的时候直接返回数组
  if (array && array.length <= 1) {
    return array;
  } else {
    //遍历当前数组
    for (var i = 0, j = array.length; i < j; i++) {
      // 标识位的作用就是用来判断是否存在NaN和空对象,第一次找到保留到新数组中
      // 然后标识位置改为false是为了再次找到的时候不推入数组
      if (isEmptyObject(array[i])) {
        emptyObjectMark && temp.indexOf(array[i]) == -1 ? temp.push(array[i]) : '';
        emptyObjectMark = false;
      } else if (array[i] !== array[i]) {
        NaNObjectMark && temp.indexOf(array[i]) == -1 ? temp.push(array[i]) : '';
        NaNObjectMark = false;
      } else
        temp.indexOf(array[i]) == -1 ? temp.push(array[i]) : '';
    }
    return temp;
  }
}
// result:[1, "true", true, 5, "F", false, undefined, null, NaN, Object, "{}", 0, "a"] 


拓展版


多维数组扁平化再去重;


回应:


留言板的小伙伴说去重深度不够。。2017/5/12


测试数组


[1, 1, [['true', true, true, [5, 'F'], false], undefined], null, null, [undefined, NaN, {}], {}, '{}', 0,1, 'a','a', NaN]


知识点


  • 数组扁平化用了递归实现
  • 代码也考虑了默认参数,防止不传递参数的时候报错
  • ES5for-in + call + for + 递归扁平化方案


function uniqueArrayWithFlattern(array) {
  var _array = array || []; // 保存传参
  // 判断空对象,这块判断折腾了许久
  function isEmptyObject(object) {
    if (Object.prototype.toString.call(object) === "[object Object]") {
      for (var i in object) {
        // 存在属性或方法,则不是空对象
        return false
      }
      return true;
    } else {
      return false;
    }
  }
  // 遍历查询判断,扁平化数组
  function forArrayFlattern(arr) {
    for (var m = 0, n = arr.length; m < n; m++) {
      if (Array.isArray(arr[m])) {
        var _tempSpliceArr = _array.splice(m, 1)[0];
        _array = _array.concat(_tempSpliceArr);
        return forArrayFlattern(_array);
      }
    }
    return uniqueArr(_array);
  }
  // 传入值必须存在,且长度小于等于1的时候直接返回数组
  if (_array && _array.length <= 1) {
    return _array
  } else {
    if (Array.isArray(_array)) {
      return forArrayFlattern(_array)
    } else {
      return _array;
    }
  }
  // 数组去重
  function uniqueArr(_array) {
    var temp = [];
    var emptyObjectMark = true; // 标识位
    var NaNObjectMark = true; // 标识位
    console.log(_array.length)
    //遍历当前数组
    for (var a = 0, b = _array.length; a < b; a++) {
      // 标识位的作用就是用来判断是否存在NaN和空对象,第一次找到保留到新数组中
      // 然后标识位置改为false是为了再次找到的时候不推入数组
      console.log(_array[a]);
      if (isEmptyObject(_array[a])) {
        emptyObjectMark && temp.indexOf(_array[a]) == -1 ? temp.push(_array[a]) : '';
        emptyObjectMark = false;
      } else if (_array[a] !== _array[a]) {
        NaNObjectMark && temp.indexOf(_array[a]) == -1 ? temp.push(_array[a]) : '';
        NaNObjectMark = false;
      } else {
        temp.indexOf(_array[a]) === -1 ? temp.push(_array[a]) : '';
      }
    }
    console.log(temp);
    return temp;
  }
}
// result:[1, null, Object, "{}", 0, "a", NaN, undefined, "true", true, false, 5, "F"]
// 用ES6来写的话,应该代码量可以稍微再精简些
目录
相关文章
|
9月前
|
JavaScript 前端开发
js实现对象数组去重
js实现对象数组去重
60 0
|
4月前
|
前端开发 JavaScript 算法
使用 JavaScript 数组方法实现排序与去重
【10月更文挑战第21天】通过灵活运用 `sort()` 方法和 `filter()` 方法,我们可以方便地实现数组的排序和去重。同时,深入理解排序和去重的原理,以及根据实际需求进行适当的优化,能够更好地应对不同的情况。可以通过实际的项目实践来进一步掌握这些技巧,并探索更多的应用可能性。
131 59
|
5月前
|
JavaScript
js数组去重
js数组去重
116 55
|
9月前
|
存储 JavaScript 前端开发
史上最详细JavaScript数组去重方法(11种)
使用set和Array.from ()方法 array.from可以将set结构转成数组
89 7
|
4月前
|
存储 JavaScript 前端开发
JavaScript数组去重的八种方法详解及性能对比
在JavaScript开发中,数组去重是一个常见的操作。本文详细介绍了八种实现数组去重的方法,从基础的双重循环和 indexOf() 方法,到较为高级的 Set 和 Map 实现。同时,分析了每种方法的原理和适用场景,并指出了使用 Set 和 Map 是目前最优的解决方案。通过本文,读者可以深入理解每种方法的优缺点,并选择最合适的数组去重方式。
200 0
|
4月前
|
JavaScript 索引
js数组去重的常见方法
js数组去重的常见方法
65 0
|
8月前
|
存储 JavaScript 前端开发
JS中数组去重的几种方法
JS中数组去重的几种方法
53 1
|
7月前
|
JavaScript
JS 数组去重(含简单数组去重【5种方法】、对象数组去重【2种方法】)
JS 数组去重(含简单数组去重【5种方法】、对象数组去重【2种方法】)
123 0
|
9月前
|
JavaScript
分享经典面试题:JS数组去重的多种方法
分享经典面试题:JS数组去重的多种方法
|
7月前
|
JavaScript 前端开发 C++
JavaScript 数组去重——普通数组去重 vs 对象数组去重
JavaScript 数组去重——普通数组去重 vs 对象数组去重
48 0

热门文章

最新文章

  • 1
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    23
  • 2
    Node.js 中实现多任务下载的并发控制策略
    32
  • 3
    【2025优雅草开源计划进行中01】-针对web前端开发初学者使用-优雅草科技官网-纯静态页面html+css+JavaScript可直接下载使用-开源-首页为优雅草吴银满工程师原创-优雅草卓伊凡发布
    25
  • 4
    【JavaScript】深入理解 let、var 和 const
    48
  • 5
    【04】Java+若依+vue.js技术栈实现钱包积分管理系统项目-若依框架二次开发准备工作-以及建立初步后端目录菜单列-优雅草卓伊凡商业项目实战
    44
  • 6
    【03】Java+若依+vue.js技术栈实现钱包积分管理系统项目-若依框架搭建-服务端-后台管理-整体搭建-优雅草卓伊凡商业项目实战
    53
  • 7
    【02】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-ui设计图figmaUI设计准备-figma汉化插件-mysql数据库设计-优雅草卓伊凡商业项目实战
    55
  • 8
    如何通过pm2以cluster模式多进程部署next.js(包括docker下的部署)
    71
  • 9
    【01】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-需求改为思维导图-设计数据库-确定基础架构和设计-优雅草卓伊凡商业项目实战
    55
  • 10
    JavaWeb JavaScript ③ JS的流程控制和函数
    62