JS回顾之Array类型

141 阅读12分钟

一、创建数组类型的方式

    第一种,使用Array构造函数 如 const arr = new Array();不推荐使用
    第二种,数组字面量表示法  如 const arr = ["a", "b", "c", "d" ]

二、数组的属性

    1、数组具有长度length属性,如上arr.length = 4
    2、数组中的每项都拥有一个唯一的索引,数组中的索引从0开始递增,如上arr数组的索引分别是0,1,2,3,arr[0] = "a",arr[1]="b" ...

三、数组操作方法

1、instanceof, 用于识别正在处理的对象的类型,返回布尔值。

    可以判断数组(Array)、对象(Object)、字符串(String)等数据类型另外

    instanceof 可以在继承关系中用来判断一个实例是否属于它的父类型,

    当然,instanceof 操作符也是存在问题的,如果你从一个框架向另一个框架传入一个数组,
    那么传入的数组与在第二个框架中原生创建的数组分别具有各自不同的构造函数。

    value instanceof Array, value是否是字符串,如果是,返回true,否则返回false

2、typeof 用于判断一个变量的类型,返回类型为字符串

    但是,在使用 typeof 运算符时采用引用类型存储值会出现一个问题,只要是引用类型,无论引用的是什么类型,它都返回
    "object",除此之外,还有两个特殊类型也会返回object,一个是 null 一个是数组

3、Array.isArray()方法

    Array.isArray(value), value如果为数组,返回true,否则返回false

4、转换方法

    toLocaleString():         拼接成了一个字符串,中间以逗号分隔 不会改变原数组
        
        const arr = ["JavaScript","真","难学"]
        
        arr.toLocaleString();       // "JavaScript,真,难学"

    toString():        拼接成了一个字符串,中间以逗号分隔 不会改变原数组
    
        const arr = ["JavaScript","真","难学"]
        
        arr.toString();         // "JavaScript,真,难学"

    valueof(): 
        valueOf() 方法返回 Array 对象的原始值。
        该原始值由 Array 对象派生的所有对象继承。
        valueOf() 方法通常由 JavaScript 在后台自动调用,并不显式地出现在代码中。不会改变原数组
    
        const arr = ["JavaScript","真","难学"]
        
        arr.valueof();      // ["JavaScript", "真", "难学"]
        
        如果渲染到节点中,会显示  JavaScript,真,难学
        

    join():       接收一个参数,即用作分隔符的字符串,然后返回包含所有数组项的字符串。不会改变原数组
    
        const arr = ["JavaScript","真","难学"]
        
        arr.join("||");         // JavaScript||真||难学
        
    
    warning: 如果数组中某一项为null或者undefined, 则会输出孔字符串""

5、栈方法

    一种让数组的行为类似于其他数据结构的方法。
    
    数组可以表现得就像栈一样,后者是一种可以限制插入和删除项的数据结构。
    
    push():         接收任意数量的参数,把它们逐个添加到数组末尾,并返回修改后数组的长度,会改变原数组
    
        const arr = [1,2,3,4]
    
        arr.push(5) // [1,2,3,4,5] // 在数组尾部添加一个值5,并返回新的数组
    
    pop():          从数组末尾移除最后一项,减少数组的 length 值,然后返回移除的项 会改变原数组
    
        cosnt arr = [1,2,3,4]
        arr.pop()  // 4  取得最后一项

6、队列方法

    队列数据结构的访问规则是 FIFO(First-In-First-Out,先进先出)。
    
    shift():   移除数组中的第一个项并返回该项,同时将数组长度减 1,会改变原数组
    
    const arr = [1,2,3,4]
    
    arr.shift()         // 1
    
    arr         // [2,3,4]
    
    unshift():   移除数组中的最后一项并返回该项,同时将数组长度减 1,不会改变原数组
    
    const arr = [1,2,3,4]
    
    arr.unshift()       // 4
    
    arr         // [1,2,3,4]

7、重排序方法

    排序方法
    
    sort(): 按升序排列数组项——即最小的值位于最前面,最大的值排在最后面。不会改变原数组,只会改变原数组排序
    
    sort是按照ASCII码来排序的,所以直接用sort(),会导致排序不是我们想要的结果.
    
        const a = [2,15,6,33,34]
        
        a.sort()        // [15, 2, 33, 34, 6]
        
    所以需要一个比较函数
        
        a.sort((a,b)=>a-b)      //[2, 6, 15, 33, 34] 
        
    reverse(): 反转数组原来的顺序   不会改变原数组,只会改变原数组排序
    
    如上数组a,经过sort排序后,我们拿到了升序的数组.那么,我想降序怎么办?
    
    有两种方法,
    
        第一种: 用reverse()方法反转数组.
            a.reverse()         // [34, 33, 15, 6, 2]
            
        第二种:用sort降序
            a.sort((a,b)=>b-a)      // [34, 33, 15, 6, 2]

8、操作方法

    concat():先创建当前数组一个副本,然后将接收到的参数,添加到这个副本的末尾,最后返回新构建的数组
    
    简单的来说,就是连接两个数组, 不会改变原数组
    
        const a=[1,2,3]  const b = [4,5,6]
        
        a.concat(b)         // [1,2,3,4,5,6]
        a       // [1,2,3]
        b       // [4,5,6]
    
    slice(): 基于当前数组中的一或多个项创建一个新数组,接受一或两个参数,即要返回项的起始和结束位置。
             不会改变原数组
    
        const a = [1,2,3,4,5,6]
    
        a.slice(1,4)        // [2,3,4]  下标为1的那项和下标为4的前一项 
                            // 可以理解为数学中的 n∈[1,4)  && n∈N


    splice(): 向数组的中部插入项 接受三个参数(起始位置,要删除的项数,需要插入的项(任意数量)) 会改变原数组
    
        删除: 只需指定 2 个参数,可以删除任意数量的项,要删除的第一项的位置和要删除的项数。
        
            const a = [1,2,3,4,5,6]
    
            a.splice(0,2)       // [1,2]
            
            a       // [3,4,5,6] 原数组下标为0开始,删除两项
        
        插入: 可以向指定位置插入任意数量的项,只需提供 3 个参数:起始位置、0(要删除的项数)和要插入的项(可以无限多个)
            
            const a = [1,2,3,4,5,6]
            
            a.splice(0,2,"删","除","前","两","项")      // [1,2]
            
            a       // ["删", "除", "前", "两", "项", 3, 4, 5, 6]
        
        替换:可以向指定位置插入任意数量的项,且同时删除任意数量的项,只需指定 3 个参数:起始位置、要删除的项数和要插入的任意数量的项
        
            const a = ["删", "除", "前", "两", "项", 3, 4, 5, 6]
            
            a.splice(0,5,"替","换","前","五","项")      // ["删", "除", "前", "两", "项"]
            
            a       // ["替", "换", "前", "五", "项", 3, 4, 5, 6]

9、位置方法

    indexOf(): 接收两个参数:要查找的项和(可选的)表示查找起点位置的索引,从数组的开头(位置 0)开始向后查找 不改变原数组
    
        const a = [ 1, 2, 3, 4, 5, 6 ]
        
        a.indexOf(6)        // 5 找到返回对应下标
        a.indexOf(7)        // -1  未找到返回-1
        
        常用于判断某个值是否存在数组里,也可以对字符串进行操作
        
        const a = "我爱JavaScript"
        
        a.indexOf("爱")      // 1 
        
        a.indexOf("爱") === -1 ? "值不存在" : "值存在"    // "值存在"
        
    lastIndexOf(): 接收两个参数:要查找的项和(可选的)表示查找起点位置的索引,从数组的末尾开始向前查找 不改变原数组
    
        同indexOf()用法一样, 区别仅在于
        
            indexOf()从数组的开头(位置 0)开始向后查找,
        
            lastIndexOf()从数组的末尾开始向前查找

10、迭代方法(实际项目中用得最多的数组方法)

    every():对数组中的每一项运行给定函数,如果该函数对每一项都返回 true,则返回 true。
    
    filter():对数组中的每一项运行给定函数,返回该函数会返回 true 的项组成的数组。
    
    forEach():对数组中的每一项运行给定函数。这个方法没有返回值。
    
    map():对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组。
    
    some():对数组中的每一项运行给定函数,如果该函数对任一项返回 true,则返回 true。
    
             以上方法都接收三个参数:数组项的值、该项在数组中的位置和数组对象本身
             以上方法都不会修改数组中的包含的值。
    
    其中最相似的是 every()和 some(),它们都用于查询数组中的项是否满足某个条件。
    对 every()来说,传入的函数必须对每一项都返回 true,这个方法才返回 true;否则,它就返回false
    而 some()方法则是只要传入的函数对数组中的某一项返回 true,就会返回 true。
    
        const a = [3,2,4,5,9,3,5]
        
        const everyResult = a.every(function(item, index, array){ 
                return (item > 2); 
            });
            
        everyResult         // true
        
        const everyResult = a.every(item => item > 3);    
        // 箭头函数可以缩短很多代码,等价于下面some方法传入的函数,后面会专门写一篇ES6箭头函数的文章
            
        everyResult         // false  // 必须所有项大于3才会返回true
        
        const someResult = a.some(function(item, index, array){ 
                return (item > 3); 
            });
            
        someResult         // true 只要有一项大于3就会返回true
        
        
     filter()函数,它利用指定的函数确定是否在返回的数组中包含某一项。常用于筛选数组
        const filterResult = a.filter(function(item, index, array){ 
                return (item > 3); 
            });
            
        filterResult         // [4,5,9,5] 
        
        
     map()函数,返回一个数组,而这个数组的每一项都是在原始数组中的对应项上运行传入函数的结果。
        const mapResult = a.map(function(item, index, array){ 
                return (item > 3); 
            });
            
                          // [  3  ,   2  ,  4  ,  5  ,  9  ,   3  ,  5 ] 
        mapResult         // [false, false, true, true, true, false, true] 输出函数运行结果(这里是比较)
        
        const a = [1,2,3,4,5]
        
        const mapResult1 = a.map((item,index) =>item*index)
        
        mapResult1          // [0, 2, 6, 12, 20]
        
        因为map和filter是项目中用得最多的方法  所以这里分析一下
        
        mapResult1 中,  
            
            第一次迭代时, item = 1 index =0  => 1*0 = 0
            第二次迭代时, item = 2 index =1  => 2*1 = 2
            第三次迭代时, item = 3 index =2  => 3*2 = 6
            第四次迭代时, item = 4 index =3  => 4*3 = 12
            第五次迭代时, item = 5 index =4  => 5*4 = 20
            
    forEach(),它只是对数组中的每一项运行传入的函数。这个方法没有返回值
        
        此方法理解为 for 方法一样, 项目中一般用map方法
        
        
        forEach(function(item, index, array){ 
            //执行某些操作
            // item  原始数组中的对应项
            // index  原始数组中的对应下标
            // array  原始数组
        });

11、归并方法

    reduce(),reduceRight(),这两个方法都会迭代数组的所有项,然后构建一个最终返回的值。
        reduce()方法从数组的第一项开始,逐个遍历到最后
        reduceRight()则从数组的最后一项开始,向前遍历到第一项
        都接收 4 个参数:前一个值、当前值、项的索引和数组对象。这
        个函数返回的任何值都会作为第一个参数自动传给下一项。第一次迭代发生在数组的第二项上,因此第
        一个参数是数组的第一项,第二个参数就是数组的第二项
        
        常用于数组中所有制求和
        
        const a = [1,2,3,4,5]
        
        const  sum = a.reduce(function(prev, cur, index, array){ 
                return prev + cur; 
                
        // 第一次执行回调函数,prev 是 0,cur 是 1。index 为0(实际并没有这一步,这一步是我自己增加的 便于理解)。
        
        // 第二次执行回调函数,prev 是 1,cur 是 2。index 为1。
        
        // 第三次执行回调函数,prev 是 3,cur 是 3。index 为2。
        
        // 第四次执行回调函数,prev 是 6,cur 是 4。index 为3。
        
        // 第五次执行回调函数,prev 是 10,cur 是 5。index 为4。
        }); 
        
        sum         // 15
        
        reduceRight() 就是顺序想法,其他和reduce()一样
        
        // reduceRight 第一次执行回调函数,prev 是 5,cur 是 4。index 为1。

下面是ES6,ES7,ES8,ES9,ES10 增加的一些数组方法,

    一、解构赋值 
    
    ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构
    
    如果你看过react或者vue项目代码,你是不是经常见到这种写法? 
        const {data1,dat2} = this.state //react
        cosnt {data1,dat2} = this.data // vue
        
        
        如果是以前,我们需要取到对象中的属性, 会怎么写?
        const obj = { a: 1, b:2, c:3}
        const a = obj.a    // 1 
        
        现在,我们用ES6的解构赋值,可以这样写,
        const obj = { a: 1, b:2, c:3}
        const {a, b, d} = obj  // 不要c
        
        a       //1
        b       //2
        d       //undefined  因为obj这个对象里没有
        
    
    数组如果是以前,我们需要取到数组中的值,
    const a = [1, 2, 3, 4];
    
    a[0]        // 1
    a[1]        // 2
    
    现在,也可以这么做.
     const [a, b, c, d] = [1, 2, 3, 4];
     
        a           //1
        b           //2
        c           //3
        d           //4
    但是数组,我只想要a和d怎么办?
    const [a,,,d] = [1,2,3,4]
    
        a           //1
        d           //4
    
    本质上,这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值
    我是不喜欢用来解构数组,但是解构赋值对象是真的好用
    
    二、includes()方法  判断一个数组是否包含一个指定的值,根据情况,如果包含则返回 true,否则返回false。 
        代替indexOf()和indexOfRight()方法,字符串同样适用,比indexOf 和 indexOfRight 更好用
    
        const a = [1, 2, 3];
        
        a.includes(2)        //  true
        
        a.includes(4)        //  false
        
        const b="123"
        
        b.includes(2)        //  true
        
        b.includes(4)        //  false
        
        
   同indexOf 的区别, indexOfRight一样 就不写了
        
        const a = ["a"];
        
        a.indexOf("a") !== -1   // true
        
        a.includes("a")         // true
        
        
        
        const a = [NaN];
        
        a.indexOf(NaN)       //-1
        
        a.includes(NaN)     //true
        
        
        
        
        const a = new Array(3);
        
        a       // [empty × 3]
       
        a.indexOf(undefined));          //-1
        
        ary1.includes(undefined)        //true
        
    三、 ...扩展运算符
    
        cosnt arr = [1,2,3,4,5]
            [...arr]
        
    见过这种...arr的写法吗,如果是以前,把数组A和数组B拼接起来,你会怎么做?是不是先想到concat()方法?
    
    const A= [1,2,3]
    const B= [4,5,6]
    
    A.concat(B)         // [1,2,3,4,5,6]
    
    现在,我们可以这样做
    
    [...A,...B]         //[1,2,3,4,5,6]
    
    我们可以这样去理解,...运算符, 相当于把数组里的所有项展开(解构)
    
    对象也是同样如此
    
    const A = {a:1,b:2}
    const B = {c:3,d:4}
    
    {...A,...B}         // {a:1,b:2,c:3,d:4}

//更多用法请移步 阮一峰-ECMAScript 6 入门

    四、Set     ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。
    
    如果是以前,我们数组去重怎么做?
    
    for循环嵌套,利用splice去重
    
    const  arr = [1,1,2,2,5,5,6,4,1,6,8,2,3,6]
    
    const newArr = arr => {
        for(let i=0;i<arr.length;i+=1){
            for(let j=i+1;j<arr.length;j+=1){
                if(arr[i]==arr[j]){ 
                    //如果第一个等于第二个,splice方法删除第二个
                arr.splice(j,1);
            j--;
                }
            }
        }
        return arr
    }
    
    newArr(arr)             // [1, 2, 5, 6, 4, 8, 3]
    
    建新数组,利用indexOf去重
    
    function newArr1(array){ 

        var arrs = []; 

        for(var i = 0; i < array.length; i++){ 
    
            if (arrs.indexOf(array[i]) == -1){ 
                //如果临时数组里没有当前数组的当前值,则把当前值push到新数组里面
                arrs.push(array[i])
            }; 
        } 
        return arrs; 
    }
    newArr1(arr)            // [1, 2, 5, 6, 4, 8, 3]
    
    当然,现在我们还可以这样做
    
    const newArr = [...arr]
    
    newArr          // [1, 2, 5, 6, 4, 8, 3]
    
    
    文章到此结束,文中如有错误,欢迎各位予以雅正.
    
    文中参考文献:<JavaScript高级程序设计(第3版)>
                [阮一峰-ECMAScript 6 入门](https://www.jianshu.com/p/d4a3baeac680)