js数组实例方法:at,concat,copyWithin

Array.prototype.at()

  1. at() 方法接收一个整数值并返回该索引对应的元素,允许正数和负数。负整数从数组中的最后一个元素开始倒数

  2. 语法

    • at(index)
  3. 参数

    • index
      • 要返回的数组元素的索引(从零开始),会被转换为整数。负数索引从数组末尾开始计数——如果 index < 0,则会访问 index + array.length 位置的元素
  4. 返回值

    • 返回数组中与给定索引匹配的元素。如果 index < -array.length 或 index >= array.length,则总是返回 undefined,而不会尝试访问相应的属性
  5. Array.prototype.myAt()

Array.prototype.myAt = function (index) {
  // 如果index大于数组的长度或者数组的长度加上index小于0,则超出数组的范围,返回undefined
  if (index < -this.length || index >= this.length) {
    return undefined
  } else if (index >= 0) {
    // index大于等于0,返回对应位置的数组元素
    return this[index]
  } else {
    // index小于0,返回数组长度加上index位置的元素
    return this[this.length + index]
  }
}

Array.prototype.concat()

  1. Array 实例的 concat() 方法用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。
  2. 语法
    • concat()
    • concat(value0)
    • concat(value0, value1)
    • concat(value0, value1, /* … ,*/ valueN)
  3. 参数
    • value1、……、valueN 可选
    • 数组和/或值,将被合并到一个新的数组中。如果省略了所有 valueN 参数,则 concat 会返回调用此方法的现存数组的一个浅拷贝。详情请参阅下文描述
  4. 返回值
    • 新的 Array 实例
  5. Array.prototype.myConcat()
Array.prototype.myConcat = function (...rest) {
  // 如果设置this为undefined或者null,报错
  if (this === undefined || this === null) {
    throw new TypeError('Array.prototype.myConcat called on null or undefined')
  }
  function parseParam(param, isThis = false) {
    let newArray = []
    // 判断param类型
    switch (Object.prototype.toString.call(param)) {
      // 如果是数组,字符串,symbol,BigInt,Boolean
      case '[object String]':
      case '[object Number]':
      case '[object Symbol]':
      case '[object BigInt]':
      case '[object Boolean]':
        // 数组类型不能设置[Symbol.isConcatSpreadable]属性,但是作为this的话需要转为Number的对象
        if (isThis) {
          newArray.push(Object(param))
        } else {
          newArray.push(param)
        }

        break
      // 如果是数组
      case '[object Array]':
        // 默认展开,如果设置了[Symbol.isConcatSpreadable]值为false时直接将param添加到新数组中 数组的[Symbol.isConcatSpreadable]默认不设置,为undefined,效果等于[Symbol.isConcatSpreadable]值为true
        if (param[Symbol.isConcatSpreadable] === false) {
          newArray.push(param)
        } else {
          // 因为存在稀疏数组的情况,需要判断值是否是empty:forEach方法会跳过empty不处理
          param.forEach((item, index) => {
            newArray[index] = item
          })
        }
        break
      default:
        // 如果是对象:类数组对象结构{0:0,1:1,length:2},需要将[Symbol.isConcatSpreadable]值设置为true才能展开加入到新数组中,否则直接整个加入到新数组
        // 其他类型数据,需要根据是否设置[Symbol.isConcatSpreadsble]值为true来判断是否需要展开加入到新数组中
        if (param[Symbol.isConcatSpreadable]) {
          // 判断是否是可迭代数组,已经设置过数组,默认为除数组和对象之外的其他可迭代模式:Set,Map,NodeList,HTMLCollection,arguments和具有length和迭代属性的object等
          // 不能和数组同时处理,因为类数组对象上没有forEach方法
          // 基础数据类型不能设置[Symbol.isConcatSpreadable]属性
          if (param[Symbol.iterator]) {
            newArray = [...param]
          } else {
            const len = param.length
            for (let i = 0; i < len; i++) {
              // 存在稀疏数组的情况
              if (param.hasOwnProperty(i)) {
                newArray[i] = param[i]
              }
            }
          }
        } else {
          newArray.push(param)
        }
        break
    }
    return newArray
  }
  // 首先需要处理this
  let newArr = parseParam(this, true)
  // 处理参数
  rest.forEach((item) => {
    // 设置前一个index值,newArr数组每次将下标为[newArr.length + index - prevIndex - 1]的值更新为item
    let prevIndex = -1
    parseParam(item).forEach((item, index) => {
      newArr[newArr.length + index - prevIndex - 1] = item
      prevIndex = index
    })
  })
  return newArr
}

Array.prototype.copyWithin()

  1. copyWithin() 方法浅复制数组的一部分到同一数组中的另一个位置,并返回它,不会改变原数组的长度
  2. 语法
    • copyWithin(target)
    • copyWithin(target, start)
    • copyWithin(target, start, end)
  3. 参数
    • target
      • 序列开始替换的目标位置,以 0 为起始的下标表示,且将被转换为整数
      • 负索引将从数组末尾开始计数——如果 target < 0,则实际是 target + array.length。
      • 如果 target < -array.length,则使用 0。
      • 如果 target >= array.length,则不会拷贝任何内容。
      • 如果 target 位于 start 之后,则复制只会持续到 array.length 结束(换句话说,copyWithin() 永远不会扩展数组)。
    • start
      • 要复制的元素序列的起始位置,以 0 为起始的下标表示,且将被转换为整数
      • 负索引将从数组末尾开始计数——如果 start < 0,则实际是 start + array.length。
      • 如果省略 start 或 start < -array.length,则默认为 0。
      • 如果 start >= array.length,则不会拷贝任何内容。
    • end(可选)
      • 要复制的元素序列的结束位置,以 0 为起始的下标表示,且将被转换为整数。copyWithin 将会拷贝到该位置,但不包括 end 这个位置的元素
      • 负索引将从数组末尾开始计数——如果 end < 0,则实际是 end + array.length。
      • 如果 end < -array.length,则使用0
      • 如果省略 end 或 end >= array.length,则默认为 array.length,这将导致直到数组末尾的所有元素都被复制
      • 如果 end 位于 start 之前,则不会拷贝任何内容。
  4. 返回值
    • 改变后的数组
  5. Array.prototype.myCopyWithin()
Array.prototype.myCopyWithin = function (target, start, end) {
  // this如果为不可迭代对象的话返回对象本身,如果为基础数据类型的话,返回基础数据类型组构成的对象
  switch (Object.prototype.toString.call(this)) {
    case '[object String]':
    case '[object Number]':
    case '[object Boolean]':
    case '[object Symbol]':
    case '[object BigInt]':
    case '[object Undefined]':
    case '[object null]':
      return Object(this)
    case '[object Array]':
      if (target === undefined) {
        return this
      }
      const len = this.length
      let newTarget = getNum(target, len),
        newStart = start ? getNum(start, len) : 0,
        newEnd = end ? getNum(end, len) : len
      if (newTarget === len || newStart === len || newStart >= newEnd) {
        return this
      } else {
        // 存在稀疏数组的情况
        // 获取到被拷贝内容组成的数组
        const copy = this.slice(newStart, newEnd)
        // 存在2种情况
        // 1: copy的数组长度大于等于从target到len长度,此时只取copy中0到len - target的值,即copy.slice(0, len - target)
        // 2: copy的数组长度等于target到len的长度,此时取所有的copy后,将原数组最后没有被复制的部分需要拼接到数组的最后
        if (copy.length >= len - newTarget) {
          return [].concat(
            this.slice(0, newTarget),
            this.slice(newStart, newEnd)
          )
        } else {
          return [].concat(
            this.slice(0, newTarget),
            this.slice(newStart, newEnd),
            this.slice(newTarget + newEnd - newStart, len)
          )
        }
      }
    default:
      let thisArr = []
      // 如果具有迭代器,则将其转为数组
      if (target !== undefined && this.hasOwnProperty('length')) {
        // 如果是具有length的可迭代对象
        const len = this.length
        let newTarget = getNum(target, len),
          newStart = start ? getNum(start, len) : 0,
          newEnd = end ? getNum(end, len) : len
        const newObj = {...this}
        while (newStart < newEnd && newTarget < len) {
          if (this.hasOwnProperty(newStart)) {
            newObj[newTarget] = this[newStart]
          }
          newStart++
          newTarget++
        }
        return newObj
      } else {
        return this
      }
  }
}

posted on 2024-12-16 20:30  shenhf  阅读(25)  评论(0)    收藏  举报

导航