数组去重的要领

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)、实例对象、其他范例的对象。

 纯对象指由字面量天生,成员中不含函数和日期、正则表达式等范例的对象。             

纯对象

一元操纵符会对对象隐式转换,对象会先挪用valueOf要领,然后是toString要领,直到能转换为基础数据范例为止。

而推断两个对象是不是是相称时,由于对象保存在堆内存,只要两个对象援用同一个地点,才会相称:

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

假如须要比较两个对象的键名键值对是不是相称,能够采纳JSON.stringify的要领转换后再比较。

实例对象

经由过程组织函数天生的对象,如许的对象和纯对象一样没法直接举行外部比较是不是相称,能够运用组织函数(类)供应静态要领或实例要领来推断是不是相称。

其他对象

指的数组、日期、正则表达式等Object衍生出来的对象,平常须要依据运用场景来组织推断要领,决议两个对象是不是相称。

比方日期对象要经由过程Data.prototype.getTime()要领来猎取时候戳推断是不是示意同一个时候,正则须要toString猎取原始字面量来推断是不是是雷同的正则表达式。

== 和 ===

假如推断元素是不是相称的要领中,采纳的是==比较运算,双方的数据会发作隐式范例转换,这就造成了影响推断效果的要素。

在推断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);
    }
    原文作者:临水照花
    原文地址: https://segmentfault.com/a/1190000009238552
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞