數組去重常常被人拿來講事,雖然在工做中不經常使用,但他可以很好的考察js基礎知識掌握的深度和廣度,下面從js的不一樣階段總結一下去重的方法。es6
該階段主要經過循環遍歷數組從而達到去重的目的數組
// 如下全部方法默認都那拿該數組進行測試 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; }
結果以下圖:
測試
雖然時間複雜度不高了,可是效果並很差。由於對象的屬性是字符串,因此會把數組全部元素默認轉化爲字符串,就會產生如下問題:es5
爲了解決類型轉換之後出現的問題,能夠用typeof操做符轉一下:code
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])
,相加以前先簡單序列化一下。索引
結果如圖: 內存
從以上能夠看出該階段的各類方法或多或少的都有一些問題,該去除的沒去掉,好比NaN。不應去的給去掉了,好比,形式相同但內存地址不一樣的對象(是否應該去掉全看你怎麼定義)。
function unique_es5(arr) { return arr.filter(function(ele,index,array) { return array.indexOf(ele) == index; }) }
結果如圖:
能夠看到除了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只是處理簡單表單驗證的玩具車語言之類的云云,我想我也會忍不住在他耳邊懟一句:那他媽是從前。