數組去重的方法

NaN

NaN屬於number,也是一種基本數據類型,只要有一邊是 NaN,那麼結果就是false正則表達式

原始值和包裝對象

包裝對象即基本數據類型通過包裝以後獲得的對象,做爲基本類型值的字符串擁有trim等方法,及length屬性,正是因爲JS代碼會對原始值作一次包裝,而後變爲了字符串對象,再執行相關的操做。數組

// "a".trim();
    
    //該過程在JS解析過程當中真實存在
    var tmp = new String("a");
    tmp.trim();

原始值和包裝對象的區別在於類型不一樣。這是最根本的區別,並且雖然是包裝"對象",但也會有對象的少部分特性,好比:函數

var A = new String("a");
    var B = new String("a");
    var C = "a";
    A == B //false
    A == C //true

對象和對象

對象能夠分爲三種:純對象(plain object)、實例對象、其餘類型的對象。prototype

純對象指由字面量生成,成員中不含函數和日期、正則表達式等類型的對象。

純對象

一元操做符會對對象隱式轉換,對象會先調用valueOf方法,而後是toString方法,直到能轉換爲基本數據類型爲止。code

而判斷兩個對象是否是相等時,由於對象保存在堆內存,只有兩個對象引用同一個地址,纔會相等:對象

{} == {}//false
    var a = new Object();
    var b = a;
    console.log(a == b)

若是須要比較兩個對象的鍵名鍵值對是否相等,能夠採起JSON.stringify的方法轉換後再比較。接口

實例對象

經過構造函數生成的對象,這樣的對象和純對象同樣沒法直接進行外部比較是否相等,可使用構造函數(類)提供靜態方法或實例方法來判斷是否相等。內存

其餘對象

指的數組、日期、正則表達式等Object衍生出來的對象,通常須要根據使用場景來構造判斷方法,決定兩個對象是否相等。字符串

例如日期對象要經過Data.prototype.getTime()方法來獲取時間戳判斷是否表示同一個時刻,正則須要toString獲取原始字面量來判斷是不是相同的正則表達式。get

== 和 ===

若是判斷元素是否相等的方法中,採用的是==比較運算,兩邊的數據會發生隱式類型轉換,這就形成了影響判斷結果的因素。

在判斷Boolea、Number、String三種類型進行不一樣類型的 == 比較時,規則是將其轉化爲數字以後再比較是否相等。

console.log( "ac" == true )//false
    console.log(123 == "123");//true

而undefined表示"缺乏值",就是此處應該有一個值,可是尚未定義。它會被轉換成數字,而轉換結果爲NaN,NaN不等於任何值,因此undefined != false;對於null來講,null表示"沒有對象",即該處不該該有值。首先調用Object.valueOf方法返回基本類型值以後在比較,因此null != false
最後一點是undefined == null,這是ECMA-262標準 11.9.3 節的規定。

去重的方法

Array.prototype.indexOf()

let arr = [12,12,9,2,0,9,8];
    /*
        例如:12第一次出如今0,以後再出現時index爲1,
        說明第二個是重複值,因此只返回第一個12,
        可是對於NaN而言indexOf只會爲-1,因此無論有幾個NaN都會直接跳過
    */
    function unique(arr){
        return arr.filter(function(value,index){
            return arr.indexOf(value) === index;
        })
    }
    
    //indexOf(NaN)則一直爲-1,數組中會出現一個或多個NaN(若是存在)
    function unique(arr){
        let ret = [];
        arr.forEach(function(value){
            if(ret.indexOf(value) === -1){
                ret.push(value);
            }
        })
        return ret;
    }
    console.log(unique(arr));

在規範中,indexOf()使用的是全等比較,只要有NaN都是沒法判斷位置直接跳過的。

全等比較不能處理NaN的相等性判斷,NaN不等於任何值,包括自己。

Array.prototype.includes()

Array.prototype.includes()是ES6中新增的方法,判斷數組中是否包含某個元素,上一中indexOf方法能夠修改成:

function unique(arr){
        let ret = [];
        arr.forEach(function(value){
            if(!ret.includes(value)){
                ret.push(value);
            }
        })
        return ret;
    }

includes()方法內部的比較方法是:"SameValueZero",詳細規則:

1. If Type(x) is different from Type(y), return false.

    2. If Type(x) is Number,then
    
        a. If x is NaN and y is NaN, return true.
        
        b. If x is +0 and y is -0, return true.
        
        c. If x is -0 and y is +0, return true.
        
        d. If x is the same Number value as y, return true.
        
        e. Return false.
    
    3. Return SameValueNonNumber(x, y).

注意:若是x、y都是NaN,則返回true,因此includes方法能夠判斷是否包含了NaN

var arr = [12,1,"d3",NaN];
    console.log(arr.includes(NaN));//true

因而可知indexOf和includes方法對NaN待的行爲不同。

其餘的方法

遍歷

遍歷是最基本也是最容易想到的方案:

function unique(arr){
        let isRepeate;
        let ret = [];
        for(var i = 0;len = arr.length,i<len;i++){
            isRepeate = false;
            for(var k = i+1;k<len;k++){
                if(arr[i] === arr[k]){
                    isRepeate = true;
                    break;
                }
            }
            if(!isRepeate){
                ret.push(arr[i]);
            }
        }
        return ret;
    }

去重的部分也是全等操做符實現的,因此對於數組中的NaN而言也會都push進入ret以後返回。

Map Key

Map是一種新的數據類型,就是key的類型沒有限制的對象,它的存取使用單獨的get、set接口。由於使用單獨的接口存取數據,因此不用擔憂key與內置屬性重名,修改上面的方法後獲得:

function unique(arr){
        let ret = [];
        let len = arr.length;
        let tmp = new Map();
        for(let i = 0;i<len;i++){
            if( !tmp.get(arr[i]) ){
                tmp.set(arr[i],1);
                ret.push(arr[i]);
            }
        }
        return ret;
    }
set

除了Map之外,還有Set這種數據類型,這是一個集合,它不容許重複元素出現。
若是重複添加相同的元素,只會儲存其中的一個,包括NaN在內。若是將這種特性與數組交換,那麼數組就能夠直接去重了。

function unique(arr){
        let ret = new Set(arr);
        return Array.from(set);
    }
相關文章
相關標籤/搜索