美文网首页
常见数组操作

常见数组操作

作者: monkeyying | 来源:发表于2019-11-27 21:01 被阅读0次

    实际工作中,程序猿对数组的操作并不陌生,讲到数组的操作方法能说出来几个,实际上我们对这些方法真的了解透了吗?会改变原数组吗,哪个方法的遍历方式速度会更快,可以中断遍历吗?这一章来研究一下常见的数组操作方法,巩固一下。


    人丑多学习.png

    一、遍历

    1、map(不改变原数组)
    //currentValue 当前值,index 当前索引,arr 源数据,thisValue可选参数,执行 callback 函数时值被用作this
    array.map(function(currentValue,index,arr), thisValue)
    array.map((currentValue,index,arr)=>{
    })
    

    不会检测空数组

    [].map((elem)=>{console.log(elem)})
    //输出:[]
    

    返回一个新数组

    var arr1=[1,2,3]
    arr1.map((elem)=>{ return elem*2 })
    //输出:[2,4,6]
    console.log(arr1)//[1,2,3]
    

    map函数将数组中的元素按顺序传入回调函数,返回一个新的函数,所以不使用这个返回新数组,可以改用forEach或者for-of


    萌萌分割图.png

    此处献上一道前端经典面试题

    [0,1,2,3,8,10].map(parseInt)
    //输出啥呢?
    

    解题思路
    懵逼1:传入的parseInt作为回调函数,如何执行
    懵逼2:如何让它正常输出数字

    解这道题,我们需要知道的知识点
    (1)、首先了解下parseInt函数 parseInt(string, radix)
    string是必传的,被解析的字符串。
    radix是可选参数,表示要解析的数字的基数。该值介于 2 ~ 36 之间。如果没传或者为0,默认是10。
    (2)、前面我们了解到,map函数接收三个参数,当前值,当前值索引和原始数据。
    这道题实际上,在执行的时候,是转换成

    //parseInt(当前值,当前值索引),返回一个新数组
    [parseInt(0,0),parseInt(1,1),parseInt(2,2),parseInt(3,3),parseInt(8,4),parseInt(10,5)]
    //[0, NaN, NaN, NaN, NaN, 5]
    
    2、forEach(不改变原数组)
    array.forEach(function(currentValue, index, arr), thisValue)
    

    map和forEach的共同点
    1、循环遍历数组中的每一项,不能改变原数组
    2、执行的回调函数接收三个参数,当前值,当前值索引,原数据
    3、只能遍历数组
    4、不能中断循环

    map和forEach的差异
    1、map会return一个新数组,forEach函数return会报错
    2、forEach对于空数组是不会执行回调函数的

    如果想让map和forEach中断循环呢?

    [1,2,33,333].map((elem,index)=>{
        if(index==2){
            break;
        }
        return elem*2
    })
    //VM176:3 Uncaught SyntaxError: Illegal break statement
    //forEach也同样会报错,此处省略啰嗦代码~
    

    在map和forEach过程中使用break都会报错,

    3、for

    最原始的遍历for写法,这种写法需要规定好遍历的边界,同时也支持遍历字符串

    const arr = [1,2,4,6]
    for(var i = 0, len = arr.length; i < len; i++){
        console.log(arr[i])
    }
    const string='劳资最漂亮'
    for(let i=0;i<string.length;i++){
        console.log(string[i])
    }
    

    for循环可以中断

    for(var i=0;i<10;i++){
        if(i==5) break;
        console.log(i)
    }//输出0 1 2 3 4
    

    for...in语句以任意顺序遍历一个对象的除Symbol以外的可枚举属性
    for...of语句在可迭代对象(包括 Array,Map,Set,String,TypedArray,arguments对象等等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句。

    var arr =[13,242,355]
    for(var i in arr){ console.log(i,arr[i])}//
    // 0 13
    // 1 242
    // 2 355
    for(var i of arr){ console.log(i,arr[i])} //在每次迭代中,将不同属性的值分配给变量。
    //13 undefined
    // 242 undefined
    // 355 undefined
    var person={name:'monkey',age:18}
    for(var i in person){ console.log(i)}// name  age
    
    其他

    前面提到的遍历的第一个参数是回调函数,第二个参数没提到,thisValue,是指传入的this指向。
    来来来,坐下继续写一道面试题,来理解一下。


    好好学习.png
    var name='香菇'
    const obj={
      name:'蓝瘦',
      say:(index)=>{
        return this.name+index
      }
    }
    const arr=[1,2,3]
    //输出??
    arr.map(obj.say,obj)// ["香菇1", "香菇2", "香菇3"]
    
    const name='香菇'
    const obj={
      name:'蓝瘦',
      say:(index)=>{
        return this.name+index
      }
    }
    const arr=[1,2,3]
    //输出??
    arr.map(obj.say,obj)//["1", "2", "3"]
    

    obj.say使用箭头函数,this指向全局windows,前面两题中唯一的差别是name变量是用const和var申明的,而const申明的变量不会挂载到windows下,所以第一道var变量打印出来的是["香菇1", "香菇2", "香菇3"],第二道const申明的变量name无值,结果是[1,2,3]

    题目再转变一下,如果不是箭头函数

    const name='香菇'
    const obj={
      name:'蓝瘦',
      say:function(index){
        return this.name+index
      }
    }
    const arr=[1,2,3]
    //输出??
    arr.map(obj.say,obj)//["蓝瘦1", "蓝瘦2", "蓝瘦3"]
    

    这里的this指向的是obj本身,this.name等于蓝瘦

    超级变变变~~~如果这个时候不传入this指向呢?

    const name='香菇'
    const obj={
      name:'蓝瘦',
      say:function(index){
        return this.name+index
      }
    }
    const arr=[1,2,3]
    //输出??
    arr.map(obj.say)//["1", "2", "3"]
    

    没错,如果没有传this指向,这个时候指向的是windows,this.name为空,输出当然就是["1", "2", "3"]

    二、增删

    1、push(改变原数组)
    var arr=[1,2,4,5,6]
    arr.push(9)//返回数组长度  6
    arr.push(10,11,12)//也可以同时追加多个元素
    console.log(arr)//[1,2,4,5,6,9,10,11,12]
    

    push操作会在数组最尾追加元素,返回数组长度,改变原数组。

    2、unshift(改变原数组)
    var arr=[1,2,4,5,6]
    arr.unshift(9)//返回数组长度  6
    console.log(arr)//[9,1,2,4,5,6]
    

    unshift操作会在数组最前添加元素,同样返回数组长度,改变原数组。

    3、pop(改变原数组)
    var arr=[1,2,4,5,7]
    arr.pop()//返回被删除的项  7
    console.log(arr)//[1,2,4,5]
    

    pop操作会在数组最后删除元素,返回删除项,改变原数组。

    4、shift(改变原数组)
    var arr=[1,2,4,5,7]
    arr.shift()//返回被删除的项  1
    console.log(arr)//[2,4,5,7]
    

    shift操作会在数组最前删除元素,返回删除项,改变原数组。

    push,pop,shift,unshift这四个方法的操作类似栈和队列方式
    栈:后进先出。通过push尾部追加和shift头部删除方法实现栈。
    队列:先进先出。通过push和尾部追加和pop头部推出实现队列。

    引入一个小知识点

    const arr=['hello','world']
    arr.length=0
    console.log(arr[0])
    

    按照上面题目,执行arr.length=0
    减少length属性的值有一个副作用,就是会删除索引位于新旧长度值之间的元素。因此arr[0]输出为undefined。所以如果要清空一个数组,可以设置数组length为0,就能实现。

    四、查

    1、find、findIndex
    var arr=[1,2,4,5,6]
    arr.find((elem,index,arr)=>{ //回调函数接收三个参数,当前值,索引和原数组
        return elem>3
    })//4
    arr.findIndex((elem,index,arr)=>{ 
        return elem>9
    })//-1
    

    find函数查找数组中符合条件的元素,并且返回符合条件的第一个值,如果不符合则返回undefined。
    findIndex函数则是返回数组中第一个符合条件的元素索引,如果不符合则返回-1。

    2、indexof
    var arr =[13,242,355]
    arr.indexOf(242)//存在则返回查找元素的索引值,否则返回-1,数组的indexof的用法和字符串的使用方式一样,返回元素的索引值。
    
    3、some
    var arr=[1,2,4,5,6]
    arr.some((elem,index,arr)=>{ //回调函数接收三个参数,当前值,索引和原数组
        return elem>3
    })//true
    

    some函数返回一个布尔值,只要数组中有一个元素满足条件,则返回true,否则返回false

    4、every
    var arr=[1,2,4,5,6]
    arr.every((elem,index,arr)=>{ //回调函数接收三个参数,当前值,索引和原数组
        console.log(elem,arr,index)
        return elem>0
    })//true
    

    every函数也是返回一个布尔值,数组中所有的元素都要满足条件才返回true,只要有一个元素不满足条件则返回false

    5、includes
    var arr=[1,2,4,5,6]
    arr.includes(1)/true
    

    includes反复也是返回一个布尔值,查询数组中是否存在元素。

    以上5种方法都可以用于查询,如果场景中需要返回true或者false,some、every、includes方法就满足了。

    五、截取

    1、slice(不改变原数组)

    slice:截取
    slice方法是截取arr中的原数,返回截取的元素集合
    array.slice(start,end)

    start:必需。规定从何处开始选取。如果是负数,那么它规定从数组尾部开始算起的位置。
    end:可选。规定从何处结束选取。该参数是数组片断结束处的数组下标。如果没有指定该参数,那么切分的数组包含从 start 到数组结束的所有元素。如果这个参数是负数,那么它规定的是从数组尾部开始算起的元素。

    var arr=[1,2,3,4,5,6]
    arr.slice(2,5)//[3,4,5] 含头不含尾截取
    console.log(arr)//[1,2,3,4,5,6]   不改变原数组
    arr.slice(3)//[4,5,6]
    

    并且,slice可以实现浅克隆

    var arr1=[1,2,3]
    var arr2=arr1.slice()
    arr1.push(4)
    console.log(arr1)//[1,2,3,4]
    console.log(arr2)//[1,2,3]
    
    2、splice(改变原数组)

    splice:粘接
    splice方法是截断一部分数据,添加新项目,此方法会改变原数组,返回被删除的项目
    array.splice(index,howmany,item1,.....,itemX)

    index:必需。整数,规定添加/删除项目的位置,使用负数可从数组结尾处规定位置。
    howmany:必需。要删除的项目数量。如果设置为 0,则不会删除项目。
    item1,.....,itemX:可选。向数组添加的新项目。

    const arr=[1,2,3,4,5]
    arr.splice(2,2,4,10,11)//返回被截断的元素[3,4] 
    console.log(arr)//改变原数组,并且拼接新增[1,2,4,10,11,5]
    

    六、反转

    1、reverse(改变原数组)

    array.reverse()

    const arr=[1,2,3,4,5]
    arr.reverse()//[5,4,3,2,1]
    console.log(arr)//[5,4,3,2,1]
    

    返回反转后的数组结果,并且会改变原数组。

    七、过滤

    1、filter(不改变原数组)

    array.filter(function(currentValue,index,arr), thisValue)

    const arr=[2,3,4,5,7,8,12]
    const arr2= arr.filter((elem,index,arr)=>{
      return elem>5
    })
    console.log(arr)//[2,3,4,5,7,8,12]
    console.log(arr2)//[7,8,12]
    

    filter函数会返回符合条件的元素集合,不改变原数据。

    八、克隆

    浅克隆
    1、JSON.parse(JSON.stringfy())
    2、array.slice(0)
    3、array.concat([])
    4、Object.assign()
    5、array.splice(0)

    深克隆

    if (!Array.isArray) {
      Array.isArray = function(arg) {
        return Object.prototype.toString.call(arg) === '[object Array]';
      };
    }
    let deepClone=(obj)=>{
      if(typeof(obj)!=='object'||typeof(obj)!=='function') return obj
      let o = Array.isArray(obj)?[]:{}
      for(var i in obj){
        if(obj.hasOwnProperty(i)){
          o[i]=typeof(obj[i])==='obj'?deepClone():obj[i]
         }
      }
      return o
    }
    

    九、扁平化

    1、flat(不改变原数组)

    flat()可以拉平数组,只能拉平一层,用Infinity关键字无论嵌套多少层,都可以转为一维数组。

    const arr=[1,2,3,[2,43,6,[33,4,[55]]]]
    console.log(arr.flat(Infinity))//[1, 2, 3, 2, 43, 6, 33, 4, 55]
    console.log(arr)//[1, 2, 3, Array(4)]
    console.log(arr.flat())//[1, 2, 3, 2, 43, 6, Array(3)]
    
    生活好累.png

    写到这有点累,明天继续补充。

    相关文章

      网友评论

          本文标题:常见数组操作

          本文链接:https://www.haomeiwen.com/subject/ppqsictx.html