数组34个方法使用方法及手撕代码

164 阅读5分钟

数组34个方法使用方法及手撕

concat

链接两个或多个数组,返回一个新数组

concat不会改变原数组

es6之后可使用扩展运算符+解构赋值替代

调用示例:

  let arr = [1,2]
  let arr1 = [3,4]
  let arr2 = arr.concat(arr1) // [1,2,3,4]

手撕代码:


/**
* 链接两个或多个数组,返回一个新数组
* @param  {...any} args 
* @returns { Array }
*/
Array.prototype.myConcat = function(...args){
  // 深拷贝(仅考虑数组情况)
  const deepCopy = (target,map = new WeakMap) =>{
    // 解决循环引用
    if(map.get(target)){
      return target
    }
    let copyTarget = []
    for (let index = 0; index < target.length; index++) {
      const type = Object.prototype.toString.call(target[index]).slice(8,-1).toLowerCase()
      if(type === 'array'){
        map.set(target,copyTarget)
        copyTarget[index] = deepCopy(target[index],map)      
      }else{
        copyTarget[index] = target[index]
      }
    }
    return copyTarget
  }
  // concat不改变原数组,所以克隆副本
  let result = deepCopy(this)
  // 多维数组扁平化
  const flatten = (arr,flattenArr) => {
    // 初始化扁平数组
    flattenArr = flattenArr ? flattenArr : []
    for (let index = 0; index < arr.length; index++) {
      const type = Object.prototype.toString.call(arr[index]).slice(8,-1).toLowerCase()
      if(type === 'array'){
        flattenArr = flatten(arr[index],flattenArr)
      }else{
        flattenArr.myPush(arr[index])
      }
    }
    return flattenArr
  }
  const flattenArr = flatten(args)
  // 合并进原数组
  for (let index = 0; index < flattenArr.length; index++) {
    result[result.length] = flattenArr[index]
  }
  return result
}

copyWithin

将元素复制到数组中的另一个位置,覆盖现有值

调用示例:

  let arr = [1,2,3,4]
  arr.copyWithin(1,2,3) // 从下标2开始到下标3复制到下标1的位置
  console.log(arr) // [1,3,3,4]
  arr.copyWithin(-1,2,3) // 起始索引接受负数,负数为数组索引倒序 
  console.log(arr) // [1,2,3,3]

手撕代码:

  /**
 * 将元素复制到数组中的另一个位置,覆盖现有值
 * @param { number } target 元素复制到的索引位置
 * @param { number } [start] 复制元素的起始索引位置
 * @param { number } [end] 复制元素结束的索引位置,默认为调用数组长度
 */
Array.prototype.myCopyWithin = function(target,start,end){
  // 负值参数从后往前计算,并处理参数大于数组索引的边界情况
  const toAbsoluteIndex = (target,length) => {
    return target < 0 ? target + length :Math.min(target,length)
  }
  target = toAbsoluteIndex(target,this.length)
  start = toAbsoluteIndex(start ?? 0,this.length)
  end = toAbsoluteIndex(end ? end : this.length,this.length)
  //  移动次数
  let count = Math.min(this.length - target , end - start)
  //  移动指针
  let inc = 1
  //  处理倒叙移动
  if(start < target && target < start + count){
    inc = -1
    target += count - 1
    start += count -1
  }
  while(count--){
    // 类数组同样可以使用,所以用in操作符来判断是否有
    if(start in this){
      this[target] = this[start]
    }
    target += inc
    start += inc
  }
  return this
}

entries,keys,values

这三个API返回的都是可迭代对象

  • entries:返回带有键/值对的iterator对象
  • keys: 返回索引键
  • values:返回索引值

迭代协议,可迭代对象,迭代器对象,生成器

后续会补充一篇新的文章

调用示例:

  let arr  = ['a','b','c']
  let entries = arr.entries()
  console.log(entries.next()) //{ value: [ 0, 'a' ], done: false }
  let keys = arr.keys()
  console.log(keys.next()) //{ value: 0, done: false }
  let values = arr.values()
  console.log(values.next()) //{ value: 'a', done: false }

手撕代码:

  /**
   * 返回带有键/值对的 array iterator对象
   */
  Array.prototype.myEntries = function*(){
    let entries = []
    for (let index = 0; index < this.length; index++) {
      const tempArr = [index,this[index]]
      entries.push(tempArr)
    }
    return yield* entries
  }

  /**
  * 返回一个包含数组索引键的array迭代器对象
  */
  Array.prototype.myKeys = function*(){
    let keys = []
    for (let index = 0; index < this.length; index++) {
      keys.push(index)
    }
    return yield* keys
  }

  /**
  * 返回一个新的array iterator对象,该对象包含数组每个索引的值。
  */
  Array.prototype.myValues = function*(){
    let values = []
    for (let index = 0; index < this.length; index++) {
      values.push(this[index])
    }
    return yield* values
  }

find,findIndex,findList,findListIndex

这4个API都接收一个回调函数,并循环数组元素去执行这个回调函数,并返回对应的下标或值

  • find 返回数组中第一个通过回调函数的值
  • findIndex 返回数组中第一个通过回调函数的下标
  • findList 返回数组中最后一个通过回调函数的值
  • findListIndex 返回数组中最后一个通过回调函数下标

调用示例:

  let arr = [
    {i:0,a:1},
    {i:1,a:1},
    {i:2,a:1},
    {i:3,a:1},
    {i:4,a:1}
  ]
  /**
   * 传入的回调函数
   * @param {*} element 当前遍历到的数组元素
   * @param {*} index 当前遍历到的数组元素
   * @param {*} array 数组本身
   */
  let callback = (element,index,array) => {
    return element.a === 1
  }

  let _find = arr.find(callback)
  let _findIndex= arr.findIndex(callback)
  let _findList = arr.findList(callback)
  let _findListIndex = arr.findListIndex(callback)
  console.log(_find) //{ i: 0, a: 1 }
  console.log(_findIndex) // 0
  console.log(_findList) // { i: 4, a: 1 }
  console.log(_findListIndex) // 4

手撕代码:

  /**
   * 返回数组中第一个通过回调函数的值
   * @param { Function } callback 回调函数
   * @param {*} thisValue 改变callback this指向
   */
  Array.prototype.myFind = function(callback,thisValue){
    let result;
    thisValue = thisValue ? thisValue : this
    for (let index = 0; index < this.length; index++) {
      if(callback.call(thisValue,this[index])){
        result = this[index]
        break
      }
    }
    return result
  }

  /**
   * 返回数组中第一个通过回调函数的下标
   * @param { Function } callback 回调函数
   * @param {*} thisValue 改变callback this指向
   */
  Array.prototype.myFindIndex = function(callback,thisValue){
    let index;
    thisValue = thisValue ? thisValue : this
    for (let i = 0; i < this.length; i++) {
      if(callback.call(thisValue,this[i])){
        index = i
        break
      }
    }
    return index
  }

  /**
   * 返回数组中最后一个通过回调函数的值
   * @param { Function } callback 回调函数
   * @param {*} thisValue 改变callback this指向
  */
  Array.prototype.myFindList =function(callback,thisValue){
    let result
    thisValue = thisValue ? thisValue : this
    for (let index = this.length - 1; index >= 0 ; index--) {
      if(callback.call(thisValue,this[index])){
        result = this[index]
        break
      }
    }
    return result
  }

  /**
  * 返回数组中最后一个通过回调函数的下标
  * @param { Function } callback 回调函数
  * @param {*} thisValue 改变callback this指向
  */
  Array.prototype.myFindListIndex =function(callback,thisValue){
    let result
    thisValue = thisValue ? thisValue : this
    for (let index = this.length - 1; index >= 0 ; index--) {
      if(callback.call(thisValue,this[index])){
        result = index
        break
      }
    }
    return result
  }

filter

返回数组中所有通过回调函数的集合

调用示例:

  let arr = [
    {i:0,a:1},
    {i:1,a:2},
    {i:2,a:3},
    {i:3,a:4},
    {i:4,a:1}
  ]
  /**
   * 传入的回调函数
   * @param {*} element 当前遍历到的数组元素
   * @param {*} index 当前遍历到的数组元素
   * @param {*} array 数组本身
   */
  let callback = (element,index,array) => {
    return element.a === 1
  }

  let _filiter = arr.filter(callback)
  console.log(_filiter) // [{i:0,a:1},{i:4,a:1}]

手撕代码:

    /**
   * filter会遍历原数组,
   * @param { Function } callback 回调函数
   * @param { * } thisValue 改变callback,this指向
   */
  Array.prototype.myFilter = function(callback,thisValue){
    thisValue = thisValue ? thisValue : this
    if(typeof callback !== 'function'){
      throw new Error(`${callback} is not a function`)
    }
    let result = []
    for (let index = 0; index < this.length; index++) {
      const tempResult = callback.call(thisValue,this[index],index,this)
      if(tempResult){
        result.push(this[index])
      }
    }
    return result
  }

fill

用一个固定的值去填充数组从起始索引到结束索引

调用示例:

  let arr = [1,2,3,4]
  arr.fill(1,1,3) // [1,1,1,4]
  arr.fill(1,2) // [1,2,1,1]
  arr.fill(1) // [1,1,1,1]

手撕代码

    /**
   * 使用定制的元素填充数组
   * @param {*} value 填充的值
   * @param { number } [start]  填充起始位置
   * @param { number } [end]  填充结束位置
   * @returns { * }
   */
  Array.prototype.myFill = function(value,start,end){
    start = start ? start : 0;
    end = end ? end : this.length
    if(typeof start !== 'number'){
      throw new Error(`${start} must be a number`)
    }
    if(typeof end !== 'number'){
      throw new Error(`${end} must be a number`)
    }
    for (let index = 0; index < this.length; index++) {
      if(index >= start && index < end){
        this[index] = value 
      }
    }
    return this
  }

every,some

这2个API都接收一个回调函数,并循环数组元素去执行这个回调函数,并返回值都是布尔值

  • every需要数组中所有元素执行这个回调函数的结果都为true,才返回true,否则返回false
  • some 只要数组中至少有一个元素执行回调函数的结果是true就会返回ture,否则返回false

调用示例:

  let arr = [1,2,3,4]
  const callback = (element,index,array) => {
    return element > 1
  }
  const _every = arr.every(callback) // false
  const _some = arr.some(callback) // true

手撕代码:

    /**
   * 数组内所有元素是否能通过callback的测试,返回一个布尔值
   * @param { Function } callback 回调函数
   * @param {*} thisValue 改变callback this指向
   * @returns { Boolean }
   */
  Array.prototype.myEvery = function(callback,thisValue){
    // 空数组在任何情况下都会返回true
    if(this.length === 0){
      return true
    }
    for (let index = 0; index < this.length; index++) {
      const result = callback.call(thisValue,this[index])
      // 只要callback的返回值不为true,直接返回false
      if(result !== true){
        return false
      }
    }
    return true
  }

/**
 * 数组中是不是至少有1个元素通过了被提供的函数测试,返回一个布尔值
* @param { Function } callback 回调函数
* @param { * } thisValue 改变callback,this指向
*/
Array.prototype.mySome = function(callback,thisValue){
  if(typeof callback !== 'function'){
    throw new Error(`${callback} is not a function`)
  }
  let result = false
  for (let index = 0; index < this.length; index++) {
    result = callback.call(thisValue,this[index],index,this)
    if(result){
      return result
    }
  }
  return result
}

forEach,map

这两个API都会接收一个回调函数,并循环数组的所有元素

  • forEach 没有返回值
  • map 返回一个新的数组

调用示例:

  let arr = [1,2,3,4]
  const callback = (element,index,array) => {
    return element*2
  }
  const _forEach = arr.forEach(callback) // undefined
  const _map = arr.map(callback) // [2,4,6,8]
  console.log(_map === arr) //false

手撕代码:

  /**
   * forEach会遍历数组所有项去执行传入的回调函数
   * forEach没有返回值
   * @param { Function } callback 回调函数
   * @param { * } thisValue 改变callback,this指向
   */
  Array.prototype.myForEach = function(callback,thisValue){
    if(typeof callback !== 'function'){
      throw new Error(`${callback} is not a function`)
    }
    for (let index = 0; index < this.length; index++) {
      callback.call(thisValue,this[index],index,this)
    }
  }

  /**
   * map会遍历数组所有项去执行传入的回调函数
   * map会返回一个新的数组
   * @param { Function } callback 回调函数
   * @param { * } thisValue 改变callback,this指向
   */
  Array.prototype.myMap = function(callback,thisValue){
    if(typeof callback !== 'function'){
      throw new Error(`${callback} is not a function`)
    }
    let result = []
    for (let index = 0; index < this.length; index++) {
      result[index] = callback.call(thisValue,this[index],index,this)
    }
    return result
  }

reduce,reduceRight

这两个API都接收一个回调函数,和一个初始值,回调函数中提供一个参数来累加元素每一次执行回调函数的结果

  • reduce 回调函数执行顺序正序,从下标0开始
  • reduceRight 回调函数执行顺序倒序,从数组最大长度开始

调用示例:

  /**
   * 
   * @param {*} previousValue 上一次调用 callbackFn 时的返回值。在第一次调用时,若指定了初始值 initialValue,其值则为 initialValue,否则为数组索引为 0 的元素 array[0]
   * @param {*} currentValue 数组中正在处理的元素。在第一次调用时,若指定了初始值 initialValue,其值则为数组索引为 0 的元素 array[0],否则为 array[1]
   * @param {*} currentIndex 数组中正在处理的元素的索引。若指定了初始值 initialValue,则起始索引号为 0,否则从索引 1 起始。
   * @param {*} array 用于遍历的数组
   */
  const callback = (previousValue,currentValue,currentIndex,array) => {
    return previousValue + currentValue
  }
  let arr = [1,2,3,4]
  // 执行0+1+2+3+4
  const _reduce = arr.reduce(callback) // 10
  // 执行4+3+2+1+0
  const _reduceRight = arr.reduceRight(callback) //10

手撕代码:

  /**对数组进行遍历,返回一个单个返回值(从左到右)
   * @param { Function } callback 回调函数
   * @param { * } initialValue 初始值
   */
  Array.prototype.myReduce = function (callback,initialValue = 0){
    if(typeof callback !== 'function'){
      throw new Error(`${callback} is not a function`)
    }
    if(typeof initialValue !== 'number'){
      throw new Error(`${initialValue} must be a number`)
    }
    for(let index = 0; index < this.length; index++){
      initialValue = callback.call(this,initialValue,this[index],index,this)
    }
    return initialValue
  }

  /**对数组进行遍历,返回一个单个返回值(从右到左)
   * @param { Function } callback 回调函数
   * @param { * } initialValue 初始值
   */
  Array.prototype.myReduceRight = function (callback,initialValue = this.length){
    if(typeof callback !== 'function'){
      throw new Error(`${callback} is not a function`)
    }
    if(typeof initialValue !== 'number'){
      throw new Error(`${initialValue} must be a number`)
    }
    for(let index = this.length - 1; index >= 0; index--){
      initialValue = callback.call(this,initialValue,this[index],index,this)
    }
    return initialValue
  }

pop,shift

这两个API都用于删除数组项,且都会改变原数组

  • pop 删除数组最后一项
  • shift 删除数组第一项

调用示例:

  let _shift = [1,2,3,4]
  let _pop = [1,2,3,4]
  _shift.shift() // [2,3,4]
  _pop.pop() // [1,2,3]

手撕代码:

  /**
   * 删除数组最后一项
   * 返回值的被删除的数组项
   * 会改变原数组
   * @returns { * }
   */
  Array.prototype.myPop = function(){
    let result
    // 空数组返回undfiend
    if(this.length === 0){
      return result
    }
    // 简易深拷贝
    result = [...this]
    // 通过改变数组长度弹出最后一个元素
    this.length = this.length -1 
    return result[result.length - 1]
  }

  /**
   * 删除数组第一项
   * 返回值是被删除的数组项
   * 会改变原数组
   * @returns { * }
   */
  Array.prototype.myShift = function(){
    let result
    // 空数组返回undfiend
    if(this.length === 0){
      return result
    }
    // 简易深拷贝
    result = [...this]
    for (let index = 1; index < this.length; index++) {
      this[index - 1] = this[index]
    }
    return result[0]
  }

unshift,push

这两个API都用于添加数组项,并返回数组新的长度

  • unshift 向数组开头添加新元素
  • push 向数组末尾添加新元素

示例代码:

  let arr = [1,2,3]
  arr.push(4)
  arr.unshift(0)
  console.log(arr) // [0,1,2,3,4]

手撕代码:

  /**
   * 向数组末尾添加新元素,并返回数组新的长度
   * @param  {...any} args 
   * @returns { number }
   */
  Array.prototype.myPush = function(...args){
    for (let index = 0; index < args.length; index++) {
      this[this.length] = args[index]
    }
    return this.length
  }

  /**
   * 向数组开头添加新元素,并返回数组新的长度
   * @param  {...any} args 
   * @returns { number }
   */
  Array.prototype.myUnshift = function(...args){
    // es6 扩展运算符 用最原生的话2个for循环也可以
    let tempArr = [...args,...this]
    for (let index = 0; index < tempArr.length; index++) {
      this[index] = tempArr[index]   
    }
    return this.length
  }

indexOf,lastIndexOf

这两个API都会返回指定元素的索引

  • indexOf 返回第一个索引
  • lastIndexOf 返回最后一个索引

调用示例:

  let arr = ['a','b','c','b','a']
  const _indexOf = arr.indexOf('a') //0
  const _lastIndexOf = arr.lastIndexOf('a') //4

手撕代码:

  /**
   * 返回指定元素的第一个索引
   * @param {*} searchElement 需要查询的值
   * @param { number } fromIndex 开始查询的位置
   * @returns { number }
   */
  Array.prototype.myIndexOf=function(searchElement,fromIndex){
    let result = -1
    // 开始查询的位置大于数组长度直接返回-1
    if(fromIndex > this.length){
      return result
    }
    for (let index = fromIndex || 0; index < this.length; index++) {
      if(searchElement === this[index]){
        result = index
        break
      }
    }
    return result
  }

  /**
   * 返回指定元素的最后一个索引
   * @param {*} searchElement 需要查询的值
   * @param { number } fromIndex 开始查询的位置
   * @returns { number }
   */
  Array.prototype.myLastIndexOf = function(searchElement,fromIndex){
    fromIndex = fromIndex ? this.length - 1 : this.length -fromIndex
    let result = -1
    for (let index = this.length; index > 0 ; index--) {
      if(this[index] === searchElement){
        result = index
        break
      }
    }
    return result
  }

includes

判断数组是否包含某个指定的值,返回一个布尔值

调用示例:

  let arr = [1,2,3]
  console.log(arr.includes(1)) // true
  console.log(arr.includes(0)) // false

手撕代码:

  /**
   * 判断数组是否包含某个指定的值
   * @param {*} searchElement  需要查找的元素值
   * @param {*} fromIndex 开始查询的位置
   * @returns {boolean}
   */
  Array.prototype.myIncludes = function(searchElement,fromIndex){
    let result;
    for (let index = fromIndex || 0; index < this.length; index++) {
      result = searchElement === this[index] ? true : false
      if(result) break
    }
    return result
  }

isArray

判断传入参数是否为数组

调用示例:

  let arr = [1,2,3]
  let string = 'test'
  console.log(Array.isArray(arr)) //true
  console.log(Array.isArray(string)) //flsae

手撕代码:

/**
 * 判断传入参数是否为数组
 * @param { * } value 
 * @returns { Boolean } 
 */
  Array.MyisArray = function(value){
    const result = Object.prototype.toString.call(value).slice(8,-1).toLowerCase()
    return result === 'array' ? true : false
  }

join,toString

将一个数组或类数组对象的所有元素连接成一个字符串并返回这个字符串

  • toSrting方法仅是在内部调用join方法将数组的每一个元素拼接成字符串返回
  • join 可以指定分割字符串的分隔符

调用示例:

  let arr =[1,2,3]
  console.log(arr.join()) // 1,2,3
  console.log(arr.toString()) // 1,2,3
  console.log(arr.join('-')) // 1-2-3

手撕代码:

  /**
   * 将一个数组或类数组对象的所有元素连接成一个字符串并返回这个字符串
   * @param { string } separator  指定一个字符串来分割数组
   */
  Array.prototype.myJoin = function(separator = ','){
    let str = this[0]
    for (let index = 1; index < this.length; index++) {
      str += `${separator}${this[index]}`
    }
    return str
  }
  
  /**
  * 内部调用join方法将数组的每一个元素拼接成字符串返回
  */
  Array.prototype.myTostring = function(){
    return this.join()
  }

from

从任何具有length属性或可迭代对象返回Array对象

调用示例:

  // 配合set可以实现数组去重
  let _set = new Set(['a','b','c','b','a'])
  const arr = Array.myFrom(_set)
  console.log(arr) // ['a','b','c']

手撕代码:

  /**
   * 从任何具有length属性或可迭代对象返回Array对象
   * @param {*} arrayLike 具有length属性或可迭代对象
   * @param {*} [mapFunction] 对数组的每一个项目调用的map函数
   * @param {*} [thisValue] 改变mapFunction this指向
   */
  Array.myFrom = function(arrayLike,mapFunction,thisValue){
    let result = []
    // 不具有length属性并且不是可迭代对象返回空数组
    if(typeof arrayLike.length === 'undefined' && !arrayLike[Symbol.iterator]){
      return result
    }
    let index = 0
    for (const iterator of arrayLike) {
      if(typeof mapFunction === 'function'){
        result[index++] = mapFunction.call(thisValue,iterator)
      }else{
        result[index++] = iterator
      } 
    }
    return result
  }

reverse

颠倒数组,会改变原数组

调用示例:

  let arr = [1,2,3]
  console.log(arr.reverse()) // [3,2,1]

手撕代码:

  /**
   * 颠倒数组,会改变原数组
   */
  Array.prototype.myReverse = function(){
    // 不会改变原数组且支持类数组对象
    let temp = Array.from(this)
    for (let index = 0; index < this.length; index++) {
      this[index] = temp[this.length - index - 1]
    }
  }

slice

返回一个新的数组,接收开始索引begin,和结束索引end

调用示例:

  let arr = [1,2,3]
  let _slice = arr.slice(0,2)
  console.log(_slice)

手撕代码:

  /**
   * 返回一个新的数组,由begin和end决定的原数组的浅拷贝
   * @param { number } begin 从该索引开始提取原数组的元素,负数为倒序
   * @param { number } end  从该索引处结束原数组元素的提取,负数为倒序
   */
  Array.prototype.mySlice = function(begin,end){
    let copyTarget = this
    let newArr = []
    begin = begin ? begin > 0 ? begin : begin + this.length : 0
    end = end ? end > 0 ? end : end + this.length : this.length
    for (let index = begin,count = 0; index < end; index++,count++) {
      newArr[count] = copyTarget[index]
    }
    return newArr
  }

spilice

删除或替换现有元素或者原地添加新元素来修改数组,并以数组形式返回被修改的内容,会改变原数组

数组API中特别强大的API,可随意的在数组的任何索引下添加或删除元素

调用示例:

  let arr = [1,2,3,4]
  arr.splice(0,2) // [3,4]
  arr.splice(0,0,5) // [5,3,4]

手撕代码:

/**
 * 删除或替换现有元素或者原地添加新元素来修改数组,并以数组形式返回被修改的内容,会改变原数组
 * @param { number } start 指定修改的开始位置
 * @param { number } [deleteCount] 表示要移出的数组元素个数
 * @param  {...any} [args] 要添加进数组的元素
 * @returns { Array } 被删除的元素组成的数组
 */
Array.prototype.mySplice = function(start,deleteCount,...args){
  let deleteArr = []
  // 如果deleteCount无值则删除开始索引后的所有元素
  if(typeof deleteCount === 'undefined'){
    deleteCount = this.length - start
  }
  // 处理负数情况
  if(deleteCount <= 0){
    deleteCount = 0
  }
  // 如果deleteCount大于start后的元素总数,则删除start后的所有元素包括start
  if(deleteCount > this.length - start){
    deleteCount = this.length - start
  }
  // 处理非整数
  if(deleteCount & 1 !== 0){
    deleteCount = parseInt(deleteCount)
  }
  /**
   * lc双指针方法移除元素
   * @param { Array } nums 源数组 
   * @param { * } val 要删除的元素
   */
  const removeElement = (nums,val) => {
    let slowIndex = 0 
    for (let index = 0; index < nums.length; index++) {
      if(nums[index] != val){
        nums[slowIndex++] = nums[index]
      }
    }
    return nums
  }
  for (let index = 0; index < deleteCount; index++) {
    const _tempDeleteCount = start + index
    // 删除索引大于数组长度则不用执行删除
    if(_tempDeleteCount < this.length){
      deleteArr.push(this[_tempDeleteCount])
      removeElement([...this],this[_tempDeleteCount])
    }
  }
  // 处理元素添加
  const addElement = (nums,index,arg) => {
    return [...nums.slice(0,index),...arg,...nums.slice(index)]
  }
  if(args.length > 0){
    const _result = addElement(this,start,args)
    // 解构赋值同concat不会改变原数组而splice会改变原数组,所以从新赋值
    for (let index = 0; index < _result.length; index++) {
      this[index] = _result[index]
    }
  }
  // 未删除元素集合
  const incomplete = [...this,...deleteArr].filter((item,index,self) => {
    return self.indexOf(item) === self.lastIndexOf(item)
  })
  // splice方法会改变原数组
  this.length = incomplete.length
  incomplete.forEach((item,index) => {
    this.fill(item,index)
  })
  // 返回值是被删除的元素集合
  return deleteArr
}

flat

可指定的深度递归遍历数组,默认递归深度为1

调用示例:

let arr = [0, 1, 2, [3, [4]]];
console.log(arr.flat()); // [0,1,2,3,[4]]
console.log(arr.flat(2)); // [0,1,2,3,4]

手撕代码:

  /**
   * 可指定的深度递归遍历数组
   * @param {number} depth 遍历深度,默认为1
   */
  Array.prototype.myFlat = function(depth = 1){
    let resultArr = []
    for (let index = 0; index < this.length; index++) {
      if(Array.isArray(this[index]) && depth > 0){
        const temp = Array.prototype.myFlat.call(this[index],depth - 1)
        // es6 数组解构
        resultArr.push(...temp)
      }else{
        resultArr.push(this[index])
      }
    }
    return resultArr
  }

flatMap

与递归深度为1的flat()相同,但可以接收一个回调函数

调用示例:

const callback = (currentValue,index,array) => {
  return  Array.isArray(currentValue) ? currentValue.flatMap(callback) : currentValue*2
}
let arr = [1, 2, [3, 4]];
let _flatMap = arr.flatMap(callback)
console.log(_flatMap) // [2,4,6,8]

手撕代码:

  /**
   * 使用映射函数映射每个元素,然后压缩成一个新数组
   * @param { Function } callback 
   */
  Array.prototype.myFlatMap = function(callback){
    let resultArr = []
    for (let index = 0; index < this.length; index++) {
      if(Array.isArray(this[index])){
        const temp = Array.prototype.myFlatMap.call(this[index],callback)
        resultArr.push(...temp)
      }else{
        resultArr.push(callback.call(this,this[index],index,this))
      }
    }
    return resultArr
  }

at

接收一个索引返回对应的元素

一般都习惯性使用arr[1]的方式

调用示例:

  let arr = ['a','b','c']
  console.log(arr.at(1)) // 'b'
  console.log(arr[1]) // 'b'

手撕代码:

  /**
   * 接收一个索引返回对应元素
   * @param {number} index 索引
   */
  Array.prototype.myAt = function(index){
    // 允许索引为负数,负数从数组最后开始倒数
    if(index < 0){
      index = index + this.length
    }
    return this[index]
  }