zoukankan      html  css  js  c++  java
  • JavaScript 基础(四):Array

    基础系列文章:

    JavaScript 基础(一):null 和 undefined

    JavaScript 基础(二):String

    JavaScript 基础(三):Number

    JavaScript 基础(四):Array

    JavaScript 基础(五):Object

    JavaScript 基础(六):Map、Set

    最近一直没有更新了。

    原因无非就是工作忙了一点。还有就是对于这个 Array 要写的东西确实比较多。

    本篇文章会分多次更新。(更新完成)

    在文章中,如果是 ES6 新增的方法,会标红作为提示。

    一、Array 构造器

    构造器:用于创建一个新的数组。

    通常有两种方式:对象字面量构造器方式

    下面是代码:

    // 对象字面量方式
    let arr = [1, 2]
    // 构造器方式
    let arr1 = Array(1, 2)
    console.log(arr === arr1)
    console.log('arr:', arr, 'arr1:', arr1)

    对于构造器方式,有两点要说明:

    1、是使用 new 还是使用函数调用方式,ECMA 给的解释是都一样;一般来说直接函数调用简便。

    2、参数,当只有一个参数时,表示创建数组的长度;0 或 2个以上参数,作为数组元素。

    var arr1 = Array(4)
    console.log('array 1 参数:', arr1)    // array 1 参数: [ <4 empty items> ]
    arr1 = Array()
    console.log('array 0 参数:', arr1)    // array 0 参数: []
    arr1 = Array(1,2,3,4)
    console.log('array 2 参数以上:', arr1)    // array 2 参数以上: [ 1, 2, 3, 4 ]

    二、ES6 新增的一些构造数组方法

    1、Array.of(ES6)

    用于将参数依次转化为数组的项。即使只有一个参数也作为数组的项

    // 和 Array 区别(一个参数)
    let arr2 = Array.of(2)
    console.log('arr2 by Array.of:', arr2)    // arr2 by Array.of: [ 2 ]
    arr2 = Array.of(4, 5, 6)
    console.log('arr2 by Array.of:', arr2)    // arr2 by Array.of: [ 4, 5, 6 ]

    2、Array.from(ES6)

    用于从一个可迭代对象创建数组。设计初衷是为了快速创建数组。

     * Array.from(arrayLike[,processingFn[,thisAry]])
     * 第一个参数:类似数组的对象,必选;
     * 第二个参数:加工函数,新数组会经过这个函数加工再返回,可选;
     * 第三个参数:this 作用域,表示加工函数执行时 this 的值,可选;

    下面展示用法:

    // 当使用 function 和箭头函数时,中间打印结果会不一样
    let obj = { 0: 'a', 1: 'b', 2: 'c', length: 3 }
    let arr3 = Array.from(
      obj,
      function(value, index){
        console.log(value, index, this, arguments.length)
        return value.repeat(3) // 必须指定返回,否则返回的是 undefined
      },
      obj
    )
    // 打印结果
    // a 0 { '0': 'a', '1': 'b', '2': 'c', length: 3 } 2
    // b 1 { '0': 'a', '1': 'b', '2': 'c', length: 3 } 2
    // c 2 { '0': 'a', '1': 'b', '2': 'c', length: 3 } 2
    
    let obj = { 0: 'a', 1: 'b', 2: 'c', length: 3 }
    let arr3 = Array.from(
      obj,
      (value, index) =>{
        console.log(value, index, this, arguments.length)
        return value.repeat(3) // 必须指定返回,否则返回的是 undefined
      },
      obj
    )
    // 打印结果
    // a 0 {} 5
    // b 1 {} 5
    // c 2 {} 5

    对于第一个参数:可迭代对象可以是 string、set、map、arguments

    // 可以作为参数的可迭代对象有:string、set、map、arguments
    console.log('array from String', Array.from('abc'))    // array from String [ 'a', 'b', 'c' ]
    console.log('array from Set', Array.from(new Set(['abc', 'def'])))   // array from Set [ 'abc', 'def' ] 
    console.log(
      'array from Map',
      Array.from(
        new Map([
          [1, 'abc'],
          [2, 'def'],
        ])
      )
    )    // array from Map [ [ 1, 'abc' ], [ 2, 'def' ] ]
    function fn() {
      return Array.from(arguments)
    }
    console.log('array from arguments:', fn(1, 2, 3))    // array from arguments: [ 1, 2, 3 ]
    

    一个重要使用场景:生成一个从0到n 的数组

    // length 就是要生成的数组个数
    console.log(
      '0-n array:',
      Array.from({ length: 10 }, (v, i) => i)
    ) 
    // 0-n array: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

     三、类型检测和原型

    1、类型检测

    现在检测数组都是用 Array.isArray(ES5 新增),对于以前的检测方法也要了解。

    在 ES5 以前,Array 的检测并没有一个统一的标准,一般使用的方法有:

    let arr5 = []
    // instanceof
    console.log('instanceof', arr5 instanceof Array)
    // constructor
    console.log('constructor:', arr5.constructor === Array)
    // Array.prototype.isPrototypeOf
    console.log('isPrototypeOf:', Array.prototype.isPrototypeOf(arr5))
    // Object.getPrototypeOf
    console.log('getPrototypeOf', Object.getPrototypeOf(arr5) === Array.prototype)
    // Object.prototype.toString
    console.log('prototype.tostring',Object.prototype.toString.apply(arr5) === '[object Array]')

    上面的检测一般情况返回都是 true。

    针对这些检测方法存在一些问题:

    a、如 let arr6 = {__proto__: Array.prototype},对 arr6 使用上面的类型检测返回的都是 true,但 arr6 并不是 Array(可以称为伪造)

    b、在多页面系统中,由于每个页面的 Array 引用地址都不一样,在一个页面检测另一个页面的 Array 就会不准确,可以直接在不同页面 

      打印 Object.getOwnPropertyNames(Array),返回的结果不一样
    c、最准确的是最后一个 Object.prototype.toString 不会存在上面问题
     
    所以一些主流的库对应 Array 的检测实现是这样的:
    if (!Array.isArray) {
      Array.isArray = function (arg) {
        return Object.prototype.toString.call(arg) === '[object Array]'
      }
    }

    看浏览器是否支持 isArray,不支持使用 Object.prototype.toString 实现 isArray 函数。

    2、原型
    Array 本质上也是 Object,所以 Array 能使用的方法都是来自于 Array.prototype。
    和 Object 一样可以通过扩展 Array.prototype 来增加数组的方法。
    而且 Array.prototype 也是一个数组
    console.log('Array.prototype is Array:', Array.isArray(Array.prototype))    // true
    console.log(
      'Array.prototype is Array:',
      Object.prototype.toString.call(Array.prototype) === '[object Array]'
    )    // true
    console.log('Array property:', Object.getOwnPropertyNames(Array.prototype))    // 返回当前 Array 的方法

    四、填鸭辩型

    在开始展示 Array 的方法前,先来说一个词:填鸭辩型。

    填鸭辩型,在这里的意思是:Array 的方法,由于设计上的巧妙可以用于类数组对象。

    下面就用 Array.push 来演示下:(使用填鸭辩型特别注意类数组对象的 length 属性

    /**
     * length 正确匹配属性个数,直接添加并 length+1
     * 1、当不存在 length 或者不能转为数值的时候,会替换第一个;length 不存在时会创建;length 为0 同;
     * 2、length 的值小于对象中属性个数;相当于在 length 处插入;
     * 3、length 的值大于等于对象中属性数,在最后添加,索引会跳跃;length 也会增加;
     */
    
    // 当 length 正确匹配属性个数
    let obj = { 0: 'football', 1: 'basketball',length :2 }
    let objPushInt = Array.prototype.push.call(obj, 'golfball')
    console.log('obj pushed:', obj) // obj pushed: { '0': 'football', '1': 'basketball', '2': 'golfball', length: 3 }
    console.log('objPushInt:', objPushInt)  // objPushInt: 3
    
    // 情形-1:length 不存在
    let obj2 = { 0: 'football', 1: 'basketball' }
    objPushInt = Array.prototype.push.call(obj2, 'golfball')
    console.log('obj2 pushed:', obj2) // obj2 pushed: { '0': 'golfball', '1': 'basketball', length: 1 }
    console.log('objPushInt:', objPushInt)  // objPushInt: 1
    // 情形-2:length 小于属性个数
    objPushInt = Array.prototype.push.call(obj2, 'volleyball') 
    console.log('obj2 pushed(lenght):', obj2) // obj2 pushed(lenght): { '0': 'golfball', '1': 'volleyball', length: 2 }
    console.log('objPushInt:', objPushInt)  // objPushInt: 2
    // 情形-3:length 大于属性个数
    obj2.length = 100
    objPushInt = Array.prototype.push.call(obj2, 'football')
    console.log('obj2 pushed(lenght==):', obj2) // obj2 pushed(lenght==): { '0': 'golfball', '1': 'volleyball', '100': 'football', length: 101 }
    console.log('objPushInt:', objPushInt)  // objPushInt: 101

    五、改变数组的9个方法

    在 MDN 上面的说法是:修改器方法,就是可以使原数组改变的方法。

    1、push

    push 向数组尾部添加一个或多个元素,并返回新数组长度;该方法可以模拟栈的入栈操作(配合 pop 实现);可以模拟出入队列(配合 shift 实现);

    可以使用“填鸭辩型”

    /**
     * 语法:array.push(element1,...,elementN)
     */
    let arr8 = ['football', 'basketball', 'volleyball']
    let pushInt = arr8.push('golfball')
    console.log('arr8 pushed:', arr8)
    console.log('pushInt:', pushInt)
    
    // 利用 push 根据 length 插入元素,可以实现数组合并(这里使用 apply 和call 的结果不一样)
    let arr8_1 = ['red', 'blue']
    pushInt = Array.prototype.push.apply(arr8, arr8_1)
    console.log('合并后数组:', arr8)
    console.log('合并后长度:', pushInt)

    2、pop

    pop 用于删除数组的最后一个元素,并返回这个元素;该方法可以模拟栈的出栈(配合 push 实现);也可以模拟队列的出队列(配合 unshift 实现);

    pop 和 push 配合使用就可以实现栈数据结构(JS 中没有栈,可以自行实现)

    可以使用“填鸭辩型”

    /**
     * 语法:array.pop()
     */
    let arr7 = ['cat', 'dog', 'cow', 'chicken', 'mouse']
    let popItem = arr7.pop()
    console.log('arr7 poped:', arr7)
    console.log('popItem:', popItem)

    3、shift

    shift 删除数组的第一个元素,并返回这个元素;可以模拟栈的出栈(配合 unshift 实现);也可以模拟队列的出队列(配合 push 实现);

    可以使用“填鸭辩型”

    /**
     * array.shift()
     */
    let arr10 = [1, 2, 3, 4, 5]
    let shiftItem = arr10.shift()
    console.log('arr10 shift:', arr10)    // arr10 shift: [ 2, 3, 4, 5 ]
    console.log('shiftItme:', shiftItem)    // shiftItme: 1

    4、unshift

    unshift 向数组头部添加元素,可添加多个,返回新数组长度;可模拟栈的入栈(配合 shift 实现);也可以模拟队列的入队列(配合 pop 实现);

    可以使用“填鸭辩型”

    /**
     * array.unshift(element1,....,elementN)
     */
    let arr11 = [1, 2, 3, 4, 5]
    let unshiftInt = arr11.unshift(10, 12)
    console.log('arr11 unshift:', arr11, ',unshiftInt:', unshiftInt)

    5、fill(ES6)

    fill 用一个固定值替换数组中从起始索引到结束索引(不包括结束索引),返回改变后数组引用(即原数组引用),原数组长度不变;

    可以使用“填鸭辩型”

    /**
     * 语法:array.fill(value[,start[,end=this.length]])
     */
    
    /**
     * 参数:
     * 1、value:要替换为的值;
     * 2、start:可选,起始位置;没有传入,全部替换;
     * 3、end:可选,结束索引,默认到最后;小于 start 不替换;
     */
    
    let arr16 = [1, 2, 3, 4, 5, 6, 7, 8, 9]
    let arrFill = arr16.fill(100, 2, 5)    // 一般示例
    let arrFill = arr16.fill(100)    // 没有起始位置,全部替换
    let arrFill = arr16.fill(100, 4)    // 有起始位置,从起始位置到最后
    let arrFill = arr16.fill(100, -20, -15)    // 不在范围内,不替换
    let arrFill = arr16.fill(100, 4, 2)    // end 小于 start,不替换

    6、sort

    用于对数组排序,返回排序后的数组;

    可以使用“填鸭辩型”

    /**
     * 语法:array.sort([comparefn])
     * 可选参数:comparefn
     *  省略时:数组元素将按照各自转换为字符的 Unicode 位点进行排序(如:Boy 排在 apple 前,数字 25 排在 8 前)
     */
    let arr12 = ['apple', 'Boy', 'cat', 'dog']
    console.log('arr12 sorted:', arr12.sort())
    arr12 = [4, 10, 20, 15]
    console.log('arr12 number sorted:', arr12.sort())
    
    /**
     * comparefn 有值:
     * 1、若 comparefn(a,b)<0,a 将排在 b 前面
     * 2、若 comparefn(a,b)=0,a 和 b 的相对位置不变
     * 3、若 comparefn(a,b)<0,a 和 b 的位置对调
     */
    // 数字的comparefn 可以这么写
    function compareNum(a, b) {
      return a - b
    }
    
    // 对于字符的,需要使用 localeCompare,排到正确顺序(本地 node 无效,浏览器下可以)
    let arr13 = ['互', '联', '网', '改', '变', '世', '界']
    let arr13_1 = arr13.sort()
    let arr13_2 = ['互', '联', '网', '改', '变', '世', '界']
    let arr13_3 = arr13_2.sort(function (a, b) {
      return a.localeCompare(b)
    })
    console.log('arr13 sort:', arr13_1, '
    by localeCompare sort:', arr13_3)

    7、reverse

    reverse 使数组倒置,返回引用;可以使用“填鸭辩型”

    let arr9 = [1, 2, 3, 4, 5]
    console.log('arr9:', arr9)
    let arr9_1 = arr9.reverse()
    console.log('reverse arr9:', arr9_1)

    8、splice

    splice 改变数组,维持原数组引用,就地删除或者新增;

    可以使用“填鸭辩型”

    /**;
     * 语法:array.splice(start,deleteCount,[item1[,item2]....])
     */
    
    /**
     * 参数说明:
     * 1、start:开始删除的索引;start 大于 length,则不删除;负值,是从 length+start 位置处删除,相加后还为负值,从0处开始删除;
     * 2、deleteCount:删除的个数;0 不删除,但应该至少添加一个元素;大于 start 后面的元素个数,后面全部删除;
     * 3、itemN:要添加的项;
     * 4、返回值:删除的数组,没有删除,返回空数组;
     */
    let arr14 = [1, 2, 3, 4, 5, 6, 7, 8, 9]
    let spliceArr = arr14.splice(4, 3, 10, 11, 12, 15)
    console.log('arr14 spliced:', arr14, '
    spliceArr:', spliceArr)
    
    spliceArr = arr14.splice(-8, 1)
    console.log('arr14 spliced start=-8:', arr14, '
    spliceArr:', spliceArr)
    spliceArr = arr14.splice(-15, 1)
    console.log('arr14 spliced start=-15:', arr14, '
    spliceArr:', spliceArr)
    
    // 删除数组中的某个元素(当不存在时,把最后一个删除了,所以要判断)
    arr14.splice(arr14.indexOf(3), 1)
    console.log('arr14 delete 3:', arr14)

    9、copyWithin(ES6)

    copyWithin 用于数组内元素的替换,替换元素和被替换元素都是数组内的;原数组长度不变;

    可以使用“填鸭辩型”

    /**
     * 语法:copyWithin(target,start,[end=this.length])
     */
    
    /**
     * 参数说明:
     * 1、target:目标元素,将被替换掉元素的索引;
     * 2、start:替换元素在数组中的起始索引;
     * 3、end:可选,默认为数组长度;end 小于 start时,不会替换;start 和 end 决定了替换和被替换的长度;
     * 4、返回:返回改变后数组的引用;
     */
    let arr15 = [1, 2, 3, 4, 5, 6, 7, 8, 9]
    // let copyWithinArr = arr15.copyWithin(6, 3)
    // let copyWithinArr = arr15.copyWithin(6, 3, 1)
    let copyWithinArr = arr15.copyWithin(6, 3, 4)
    console.log('arr15 copyWinthin:', arr15, '
    copyWithinArr:', copyWithinArr)

    六、不改变数组的9个方法

    这些方法在 MDN 上面是:访问方法。不会改变自身,会返回一个新的数值或一个期望值。

    1、join

    join 用于使用给定的字符串连接数组的各个项。

    可以使用“填鸭辩型”

    /**
     * join 用指定的字符连接数组中的所有项,并返回连接后的字符串;
     * 默认不传值,是用【,】连接
     */
    let arr18 = ['my', 'name', 'is', 'ZHT']
    let arrJoin = arr18.join()
    arrJoin = arr18.join(' ')
    arrJoin = arr18.join('-')

    2、toString

    toString 用于连接数组的各个项,并返回这个字符串;

    /**
     * 内在操作是:每个项目 toString,后使用 join 连接各个项;所以不能使用“填鸭辩型”,Object 中没有 join(虽然 Array.join 可以使用在 Object 上面,但是 Object 本身没有)
     * 所以是用【,】连接的各个项
    */ let arr20 = [1, 2, 3, 4, 5, 6] let arrToString = arr20.toString() console.log('arr20:', arr20, ' arrToString:', arrToString)

    3、toLocaleString

    toLocaleString 和上面的 toString 一样,只是在转换的时候本地化

    4、toSource

    toSource 返回当前数组字面量的字符串。这个一般没有被实现。

    5、indexOf

    indexOf 用于从数组中查找第一个和给定值相等的索引,不存在返回 -1

    /**
     * 使用的是严格相等
     * 语法:array.indexOf(element[,start])
     * start 是开始查找位置,默认 0;
     */
    let arr21 = [1, 2, 3, 4, 5, 6, 7, 8]
    let arrIndexInt = arr21.indexOf(5)
    console.log('arr21:', arr21, '
    arrIndexInt:', arrIndexInt)
    
    // 找出数组中某一个值的所有出现位置
    function GetArrayAllIndex(arr, value) {
      let indices = []
      let idx = arr.indexOf(value)
      while (idx !== -1) {
        indices.push(idx)
        idx = arr.indexOf(value, idx + 1)
      }
      return indices
    }
    let allIndex = GetArrayAllIndex(
      ['a', 'b', 'c', 'd', 'e', 'a', 'g', 'a', 'a'],
      'a'
    )
    console.log('allIndex:', allIndex)    // allIndex: [ 0, 5, 7, 8 ]

    6、lastIndexOf

    lastIndexOf 从数组中查找给定值的索引,是从数组尾部向前查找。

    start 为负值时,从(start + length) 处开始查找

    7、includes(ES6)

    includes 验证数组中是否包含给定值。

    /**
     * includes 用于判断数组中是否存在要查找的值;有 true ,没有 false;
     * 语法:array.includes(value[,start])
     */
    
    let arr22 = [1, 2, 3, 4, 5, 6, 7]
    console.log('arr includes 5:', arr22.includes(5))
    
    /**
     * 和 indexOf 有一点区别:
     * includes 可以判断 NaN ,indexOf 不可用
     */
    
    let arr22_1 = [1, 2, 3, 4, 5, NaN, 7]
    console.log('arr includes NaN:', arr22_1.includes(NaN)) // true
    console.log('arr indexOf NaN:', arr22_1.indexOf(NaN)) // -1

    8、concat

    concat 用于连接数组、多个数组、数组项等,并返回新的数组;

    可以使用“填鸭辩型”

    /**
     * concat 用于连接数组、多个数组、值到当前数组尾部,并返回新的数组;原数组不变;会对传入的值扁平化处理(只能处理一级,对于嵌套的不行)。
     * 返回的数组中原数组中的项是--浅复制--过去的;
     */
    let arr17 = [{ a: 1 }, 2, 3, 4]
    let arrConcat = arr17.concat(5, [6, 7, [8,9]])
    console.log('arrConcat:', arrConcat)  // [ { a: 1 }, 2, 3, 4, 5, 6, 7, [ 8, 9 ] ]
    console.log('arr17[0] === arrConcat[0]:', arr17[0] === arrConcat[0])  // true

    9、slice

    slice 用于从原数组浅复制一部分项到新数组;

    可以使用“填鸭辩型”

    /**
     * slice 用于从原数组【浅复制】一部分项到新数组;返回这个新数组,原数组不变
     */
    
    /**
     * 语法:array.slice([start[,end]])
     * 参数:
     * 1、start:可选,开始索引;负值,表示倒数第几个开始,默认 0;
     * 2、end:可选,结束索引;不包括该项;默认 length;
     */
    let arr19 = [0, 1, 2, 3, 4, 5, 6, 7]
    let arrSlice = arr19.slice(1, 5)
    console.log('arr19:', arr19, '
    arrSlice:', arrSlice)
    
    // 当数组中有引用类型存在时,slice 生成的新数组是浅复制的
    // 当新数组中的值改变时,原数组也会改变
    let arr19_1 = [{ a: 100 }, 101, 102, 103]
    let arrSlice_1 = arr19_1.slice(0, 3)
    console.log('arr19_1:', arr19_1, '
    arrSlice_1:', arrSlice_1)
    arrSlice_1[0].a = 200
    console.log('arr19_1:', arr19_1, '
    arrSlice_1:', arrSlice_1)

    七、数组的12个遍历方法

    1、forEach

    forEach 对数组的每一项执行传入的函数,如果函数操作了项,原数组改变;返回 undefined

    /**
     * forEach 对数组中的每个项都执行一次传入的函数;如果函数操作了项,原数组改变;返回值 undefined;
     * 对于删除的、新增的、未初始化的会跳过,不执行;
     * 语法:array.forEach(fn[,thisArg])
     * fn:每一次执行的函数
     * thisArg:可选,传入的要绑定的 this 值
     */
    
    let arr23 = [1, 2, 3, 4, 5, 6, 7]
    arr23.forEach((item, index) => {
      console.log('第', index, '个的平方是:', item * item)
    })
    
    // 稀疏数组操作(未初始化的会跳过),null 不会跳过,会转为 0(有点坑)
    arr23 = [1, 2, 3, null, , 6, 7]
    arr23.forEach((item, index) => {
      console.log('第', index, '个的平方是:', item * item)
    })

    注意:

      即使传入的函数显示返回值,最终 forEach 也是 undefined

    let arr23 = [1, 2, 3, 4, 5, 6, 7]
    const arr23_for = arr23.forEach((item, index) => {
      return item * item
    })
    console.log(arr23_for)    // undefined

    2、map

    map 对数组的每一种执行传入的函数,并根据函数返回值组成一个新的数组(function 默认返回 undefined)

    /**
     * map 用于返回一个新数组,是由原数组的每一个项执行一次给定的函数返回的结果;如果函数改变了原数组的项,原数组改变;
     * 对于删除的、新增的、未初始化的会跳过,不执行;null 不会跳过,会转为 0
     */
    let arr26 = [1, 2, 3, 4, 5, 6,null, 7, 8]
    let arrMap = arr26.map((item) => item * 2)  // 只有一句表达式,没有中括号,默认返回表达式的值
    arrMap = arr26.map((item) => {item * 2})  // 返回 undefinde 组成的数组

    3、find(ES6)

    find 根据传入的函数,查找出第一个符合的项,并返回这个项;不存在返回 undefined

    let arr28 = [1, 2, 3, 4, 5, 6, 7, 8]
    function getNumber(value) {
      return value === 5
    }
    console.log('arr28 find 5:', arr28.find(getNumber))    // 5

    4、findIndex(ES6)

    findIndex 根据传入的函数,查找出第一个符合的项,并返回项索引;不存在返回 -1

    let arr28 = [1, 2, 3, 4, 5, 6, 7, 8]
    function getNumber(value) {
      return value === 5
    }
    console.log( 'findIndex 5:',arr28.findIndex(getNumber))    // 4
    // 和 indexOf 区别,传入的参数不一样;这里是函数,能做的事情更多,更复杂

    5、every

    every 用于验证数组内的所有项是否都符合传入函数的验证

    /**
     * 只有全部符合才返回 true ,否则 false
     */
    let arr24 = [1, 2, 3, 4, 5, 6, 7, 8]
    console.log('arr24 all >0:',arr24.every((item) => item > 0)) // true

    6、some

    some 正好和 every 相反,只有有一个满足传入函数验证,就返回 true。

    let arr24 = [1, 2, 3, 4, 5, 6, 7, 8]
    console.log('arr24 have >5:',arr24.some((item) => item > 5))  // true
    
    // 数组交集(可对比多个数组)
    const intersection = (list, ...args) => {
      console.log(args)
      return list.filter((item) => args.some((list) => list.includes(item)))
    }
    
    console.log(intersection([2, 1], [2, 3], [1, 4, 6])) // [2,1]

    7、filter

    filter 用于筛选数组中满足给定条件的项,并返回这些项的数组。

    let arr25 = [1, 2, 3, 4, 5, 6, 7, 8]
    console.log('arr25 中大于5的项:',arr25.filter((item) => item > 5))
    
    // 下面是一个场景的使用
    // 使用 filter 创建具有非0 id 的json
    var arrJson = [
      { id: 15 },
      { id: -1 },
      { id: 0 },
      { id: 3 },
      { id: 12.2 },
      {},
      { id: null },
      { id: NaN },
      { id: 'undefined' },
    ]
    function isNumber(obj) {
      return obj !== undefined && typeof obj === 'number' && !isNaN(obj)
    }
    function filterById(item) {
      if (isNumber(item.id) && item.id !== 0) {
        return true
      }
      return false
    }
    let arrJsonNoZeroId = arrJson.filter(filterById)
    console.log('arrJsonNoZeroId :', arrJsonNoZeroId)

    8、reduce

    reduce 接收一个函数,用于汇总数组所有的项,并返回这个汇总结果。

    以前一直以为这个是 ES6 的新方法,其实是挺早就有的。IE9 也支持该方法。

    /**
     * 语法:array.reduce(callback(accumulator,currentValue[,index[,array]])[,initialValue])
     * 参数:
     *  1、callback:传入的汇总函数
     *    a、accumulator:是 callback 上一次调用返回的值,或者initialValue的值
     *    b、currentValue:当前项
     *    c、当前项的索引
     *    d、array 当前数组
     * 2、initialValue:callback 第一次调用的 accumulator 值
     *    a、未传值时,数组的第一个为该值,上面的回调函数会执行 length-1 次
     *    b、传值,会执行 length 次
     */
    let arr27 = [1, 2, 3, 4, 5, 6, 7, 8, 9]
    console.log(
      'arr27 reduce +:',
      arr27.reduce((pre, cur) => pre + cur)
    )
    console.log(
      'arr27 reduce + 20:',
      arr27.reduce((pre, cur) => pre + cur, 20)
    )
    
    // reduce 示例
    // 1、将二维数组转为一维数组(扁平化处理)
    let arr27_1 = [
      [1, 2],
      [3, 4],
      [5, 6],
      [7, 8],
    ]
    let arrReduce = arr27_1.reduce(function (a, b) {
      return a.concat(b)
    }, [])
    console.log('二维数组转一维数组:', arrReduce)
    
    // 2、计算每个元素出现的次数(去重也可以)
    let arr27_2 = ['abc', 'bcd', 'def', 'dgf', 'abc', 'def', 'abc']
    function getNames(names, name) {
      if (name in names) {
        names[name]++
      } else {
        names[name] = 1
      }
      return names
    }
    let names = arr27_2.reduce(getNames, {})
    console.log(
      '数组元素出现次数:',
      names,
      '
    去重后的数组:',
      Object.getOwnPropertyNames(names)
    )
    
    // 3、根据属性,对一组对象分类
    let arr27_3 = [
      { name: 'abc', age: 20 },
      { name: 'dbg', age: 21 },
      { name: 'edv', age: 20 },
    ]
    function groupBy(objectArr, property) {
      return objectArr.reduce(function (acc, curItem) {
        let key = curItem[property]
        if (acc[key]) {
          acc[key].push(curItem)
        } else {
          acc[key] = [curItem]
        }
        return acc
      }, {})
    }
    console.log('对象数组分类:', groupBy(arr27_3, 'age'))

    9、reduceRight

    reduceRight 的使用和 reduce 是一样的,只是在执行的时候是从右侧开始。

    10、entries(ES6)

    11、keys(ES6)

    12、values(ES6)

    把上面三个放在一起来说。

    共同点:返回的都是一个迭代器

    不同点:迭代器内容不同,entries 是项和索引的键值对迭代器;keys 索引的迭代器;values 项的迭代器;

    let arr29 = [1, 2, 3, 4, 5, 6, 7, 8]
    console.log(
      'arr entries:',
      arr29.entries().next(),    // arr entrie: { value: [ 0, 1 ], done: false } 
      '
    keys:',
      arr29.keys().next(),    // key: { value: 0, done: false }
      '
    values:',
      arr29.values().next()    // value: { value: 1, done: false }
    )

    到这里 Array 的已经写完了,后续有新功能会继续更新。

  • 相关阅读:
    iOS 获取全局唯一标示符
    iOS 获取全局唯一标示符
    如何让UIViewController自动弹出PickerView
    如何让UIViewController自动弹出PickerView
    防止NSTimer和调用对象之间的循环引用
    防止NSTimer和调用对象之间的循环引用
    inputAccessoryView,inputView
    @encode关键字
    @encode关键字
    用 Flask 来写个轻博客 (11) — M(V)C_创建视图函数
  • 原文地址:https://www.cnblogs.com/zhurong/p/14299245.html
Copyright © 2011-2022 走看看