摘要:阶段该阶段主要通过循环遍历数组从而达到去重的目的多次循环去掉重复元素以下所有方法默认都那拿该数组进行测试结果如下图可见除了没有去掉,其他效果都还挺好。
ES3阶段数组去重经常被人拿来说事,虽然在工作中不常用,但他能够很好的考察js基础知识掌握的深度和广度,下面从js的不同阶段总结一下去重的方法。
该阶段主要通过循环遍历数组从而达到去重的目的
多次循环去掉重复元素
// 以下所有方法默认都那拿该数组进行测试 var array = [1, 1, "1", "1", null, null, undefined, undefined, new String("1"), new String("1"), /a/, /a/, NaN, NaN,{},{},[],[],{name: "eric",sex: "male"},{sex: "male",name: "eric"}]; function unique_es3_on2 (arr) { var len = arr.length, i = 0, j, flag, ret = []; for (; i < len ; i++) { flag = true; for (j = i+1 ; j < len ; j++) { if (arr[i] === arr[j]) { flag = false; break; } } if(flag) { ret.push(arr[i]); } } return ret; } unique_es3_on2(array)
结果如下图:
可见除了NaN没有去掉,其他效果都还挺好。原因就是NaN===NaN的结果是false。还有就是使用嵌套的循环,时间复杂度高,性能不是很好。
借助新的对象单次循环去掉重复元素
function unique_es3_on(arr) { var obj = {}, i, len = arr.length, ret = []; for(i = 0; i < len ; i++) { if(!obj[arr[i]]) { obj[arr[i]] = true; ret.push(arr[i]); } } return ret; }
结果如下图:
虽然时间复杂度不高了,但是效果并不好。因为对象的属性是字符串,所以会把数组所有元素默认转化为字符串,就会产生以下问题:
数值1和字符串"1"以及包装类型new String("1"),转化为字符串以后是相同的会被去掉。
对象转化为字符串以后会被误判,[]==>"",{}==>"[object Object]",还有就是形式相同,内存地址不同的对象会被去除。
为了解决类型转换以后出现的问题,可以用typeof操作符转一下:
function unique_es3_on(arr) { var obj = {}, i, len = arr.length, str, ret = []; for(i = 0; i < len ; i++) { str = typeof arr[i] + arr[i]; if(!obj[str]) { obj[str] = true; ret.push(arr[i]); } } return ret; }
结果如图:
可以看到类型转换的问题基本解决,但对象部分基本都被去除了,因为他们和字符串相加时还是会发生转化,解决的方案是把上面的str换成str = typeof arr[i] + JSON.stringify(arr[i]),相加之前先简单序列化一下。
结果如图:
ES5阶段从以上可以看出该阶段的各种方法或多或少的都有一些问题,该去除的没去掉,比如NaN。不该去的给去掉了,比如,形式相同但内存地址不同的对象(是否应该去掉全看你怎么定义)。
function unique_es5(arr) { return arr.filter(function(ele,index,array) { return array.indexOf(ele) == index; }) }
结果如图:
ES6阶段可以看到除了NaN,其他表现都是正常的。其中indexOf对于NaN总是返回-1,所以导致误判。
let unique_includes = (arr) => { let newArr = []; arr.forEach(function(item){ if(!newArr.includes(item)){ newArr.push(item); } }); return newArr; }
结果如图:
可以看到结果是符合预期的,es6中数组的扩展方法includes解决了用indexOf的弊端(不够直观,结果还要和索引进行比较。对NaN的误判)。
let unique_set = (arr) => { return [...new Set(arr)]; }
结果和includes方法一样,此处利用es6新增数据结构set的特性,达到去重的目的。
let unique_map = (arr) => { let ret = [], m = new Map(); for(val of arr) { if(!m.get(val)) { m.set(val , true); ret.push(val); } } return ret; }
结果和includes一样:
此处利用es6新增数据结构map的特性,之前的键值对集合(js对象),只能用字符串当作健,map这种数据结构打破了这一限制,各种类型的值都可以当作健,而且map的健是跟内存地址绑定的,只要内存地址不同就认为是不同的健,解决了之前形式相同而内存地址不同被去掉的问题。对于简单数据类型,只要严格相等就认为是相同的健,特例NaN也认为是相同的健。所以就解决了之前的两个大难题。
总结虽然只是一个简单的去重问题,但这一路实践下来,可以看到js越来越强大,功能也越来越完善,同时也越来越优雅。现在再听到有人说,js只是处理简单表单验证的玩具车语言之类的云云,我想我也会忍不住在他耳边怼一句:那他妈是从前。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/87231.html
摘要:基本操作数组去重写在前面数组去重经常出现在前端招聘的笔试题里,比如有数组,请用实现去重函数,使得返回作为笔试题,考点有二正确。基本介绍文章主要是对数组去重的常用方法进行介绍。 js基本操作-数组去重 写在前面 JavaScript 数组去重经常出现在前端招聘的笔试题里,比如: 有数组 var arr = [a, b, c, 1, 0, c, 1, , 1, 0],请用 JavaScr...
摘要:设计模式是以面向对象编程为基础的,的面向对象编程和传统的的面向对象编程有些差别,这让我一开始接触的时候感到十分痛苦,但是这只能靠自己慢慢积累慢慢思考。想继续了解设计模式必须要先搞懂面向对象编程,否则只会让你自己更痛苦。 JavaScript 中的构造函数 学习总结。知识只有分享才有存在的意义。 是时候替换你的 for 循环大法了~ 《小分享》JavaScript中数组的那些迭代方法~ ...
摘要:同行这么做使用实现圆形进度条前端掘金在开发微信小程序的时候,遇到圆形进度条的需求。实现也谈数组去重前端掘金的数组去重是一个老生常谈的话题了。百度前端技术学院自定义前端掘金一标签概念元素表示用户界面中项目的标题。 闲话图片上传 - 掘金作者:孙辉,美团金融前端团队成员。15年毕业加入美团,相信技术,更相信技术只是大千世界里知识的一种,个人博客: https://sunyuhui.com ...
摘要:同行这么做使用实现圆形进度条前端掘金在开发微信小程序的时候,遇到圆形进度条的需求。实现也谈数组去重前端掘金的数组去重是一个老生常谈的话题了。百度前端技术学院自定义前端掘金一标签概念元素表示用户界面中项目的标题。 闲话图片上传 - 掘金作者:孙辉,美团金融前端团队成员。15年毕业加入美团,相信技术,更相信技术只是大千世界里知识的一种,个人博客: https://sunyuhui.com ...
阅读 3563·2023-04-26 00:05
阅读 953·2021-11-11 16:55
阅读 3522·2021-09-26 09:46
阅读 3516·2019-08-30 15:56
阅读 908·2019-08-30 15:55
阅读 2933·2019-08-30 15:53
阅读 1939·2019-08-29 17:11
阅读 813·2019-08-29 16:52