JS数组里的一些常用方法,以及如何简单手写实现

77 阅读3分钟

1、会修改原数组的方法

  • 1.1 push: 向数组末尾添加一个或多个元素,数组长度增加相应长度,返回数组长度

  • 1.2 pop: 删除数组末尾元素,数组长度减一,返回被删除的元素

  • 1.3 unshift: 向数组首部添加一个或多个元素,数组长度增加相应长度,返回数组长度

  • 1.4 shift: 删除数组首部元素,数组长度减一,返回被删除的元素

  • 1.5 reverse: 翻转数组
    手写实现:

    // 遍历数组前一半元素,让其与数组对应的后一半元素交换
    Array.prototype.myReverse = function(){
      const len = this.length
      const mid = Math.floor(len/2)
      for(let i=0; i<mid; i++) {
        let tmp = this[i]
        this[i] = this[len-i-1]
        this[len-i-1] = tmp
      }
      return this
    }
    
  • 1.6 splice: 用于增删改原数组,splice(index, count, ...items[]) 第一个参数是数组的目标下标位置index,第二个参数是从目标位置开始(包括目标位置)往后count个元素,第三个参数是将这count个元素替换为传入的...items[]
    手写实现:

      Array.prototype.mySplice = function(index, count, ...args) {
      /* 删除count个元素,添加args.length个元素,所以,我们需要将index+count位置后面的所有元素
        向左或者向右移动|args.length-count|个位置,给删除以及添加腾位置
      */
      let argLen = args.length
      let arrLen = this.length
      const retArr = []
      // 如果count为undefined,则需要删除index以及之后的所有元素,需要将count置为数组长度减index
      if(!count) count = arrLen - index
      // 需要移动的步数
      let moveStep = args.length - count
      // 首先将要被删除的元素存到一个数组里,之后需要返回删除的数组
      for(let i=index; i<count+index; i++) {
        retArr.push(this[i])
      }
      // 若添加的元素比删除的元素多,则将index+count位置之后的元素向右移动moveStep步
      if(moveStep >= 0) {
        for(let i=arrLen-1; i>=index+count; i--) {
          this[i+moveStep] = this[i]
        }
      } else {
        moveStep = Math.abs(moveStep)
        // 否则向左移动
        for(let i=index+count; i<arrLen; i++) {
          this[i-moveStep] = this[i]
        }
        this.length -= moveStep
      }
      // 再将index以及之后args.length个元素放到index以及index之后
      for(let i=index; i<argLen+index; i++) {
        this[i] = args[i-index]
      }
      return retArr
    }
    
  • 1.7 sort: 传入一个回调函数,用于给数组排序,回调函数接收两个参数,a,b,sort会遍历一遍数组,依次将相邻的两个元素传给回调函数的a,b,若回调函数返回值大于0,则b会在a的前面,小于0,a会在b的前面,等于0,ab的相对位置不变
    手写实现:(以简单的冒泡排序实现,实际的sort实现要更复杂,更高效)

    // 大概是这样,简单实现
    Array.prototype.mySort = function(cbFn) {
      const len = this.length
      for(let i=0; i<len-1; i++) {
        for(let j=0; j<len-i-1; j++) {
          if(cbFn(this[j],this[j+1]) > 0) {
            let tmp = this[j]
            this[j] = this[j+1]
            this[j+1] = tmp
          }
        }
      }
      return arr
    }
    

2、不修改原数组的方法

  • 2.1 map map方法接收一个回调函数,回调函数接收一个参数,map方法会遍历数组,将每个元素作为参数传入回调函数,每次调用回调函数,会将返回值替换为当前遍历到的数组元素的值
    手写实现:

    // 大概是这样
    Array.prototype.myMap = function(cbFn) {
      const retArr = [];
      const len = this.length
      for(let i=0; i<len; i++) {
        retArr.push(cbFn(this[i]))
      }
      return retArr
    }
    
  • 2.2 reduce 此方法接收两个参数,第二个参数可选,第一个参数是一个回调函数,回调函数接收两个参数,第一次调用时,若reduce有接收第二个参数,则回调函数的第一个参数为reduce接收的第一个参数,第二个参数为数组的第一项;若reduce没有接收第二个参数,则回调函数的第一个参数为数组的第一项,第二个参数为数组的第二项,之后每次调用,数组元素向后遍历,回调函数的第一个参数为上一次回调函数调用的返回值,第二个参数为当前遍历到的数组元素,实现不断地累计,获取到累计值
    手写实现:

    // 大概这样实现
    Array.prototype.myReduce = function(cbFn, start) {
      const len = this.length
      let acc = start ? start : this[0]
      let startIdx = start ? 0 : 1
      // 若数组元素小于2且没有start
      if((len === 1 && !start) || len === 0) {
        return 
      }
      for(let i=startIdx; i<len; i++) {
        acc = cbFn(acc, this[i])
      }
      return acc
    }
    
  • 2.3 concat 接收一个数组,将此数组与接收的数组连起来,返回一个新数组
    手写实现:

    Array.prototype.myConcat = function(otherArr) {
      return [...this, ...otherArr]
    }
    
  • 2.4 filter 传入一个回调函数,回调函数里接收的参数是原数组的每一项,回调函数需要返回一个布尔值,若为true将数组里的这一项加入新数组
    手写实现:

    Array.prototype.myFilter = function(cbFn) {
      let len = this.length
      const retArr = []
      for(let i=0; i<len; i++) {
        let tmpBool = cbFn(this[i]);
        if(tmpBool) retArr.push(this[i])
      }
      return retArr
    }
    
  • 2.5 flat 传入一个number,不传默认为1,指定深度,打平数组
    手写实现

    // 递归地调用flat,将数组打平到depth深度
    Array.prototype.myFlat = function(depth=1) {
      if(depth === 0) {
        return this
      }
      const ret = []
      let len = this.length
      for(let i=0; i<len; i++) {
        if(Array.isArray(this[i])) {
          ret.push(...(this[i].myFlat(depth-1)))
        } else {
          ret.push(this[i])
        }
      }
      return ret
    }
    

大致写这么多吧,数组方法还有挺多的,如some,every,includes,indexOf,用起来也都挺简单的,实现也都挺简单的,找准方法接收什么参数,接收回调的话,回调需要接收什么参数,它实现什么效果,知道了这些,按照它需要实现的效果来就行了,当然我的实现也都是最简单的方式,不是完善的方式,还有很多边界条件没考虑,数组的使用还是挺简单的。