ES6 copyWithin

在这里插入图片描述

前言

  copyWithin 用于浅复制数组的一部分到另一位置。

[1, 2, 3, 4, 5].copyWithin(0, 2, 4) // [3, 4, 3, 4, 5]

  其中参数分别为target(复制到的索引)、start(开始复制的索引)、end(结束复制的索引,不包括end位置的元素)。

在这里插入图片描述

参数

  参数start默认值为0end默认值为数组长度,若参数为负数,函数toAbsoluteIndex会将其转换为正数。

function toAbsoluteIndex(target, len) {
  return target < 0 ? len + target : Math.min(target, len)
}

Array.prototype.copyWithin = function (target, start, end) {
  var len = this.length
  target = toAbsoluteIndex(target, len)
  start = toAbsoluteIndex(start || 0, len)
  end = end === undefined ? len : toAbsoluteIndex(end, len)
  var count = Math.min(len - target, end - start)
  var inc = 1

  while (count--) {
    if (start in this) {
      this[target] = this[start]
    }

    target += inc
    start += inc
  }

  return this
}

移动次数

  count为移动次数,取值分为两种情况,第一种由lengthtarget决定。

[1, 2, 3, 4, 5].copyWithin(-2) // [1, 2, 3, 1, 2]

  以上相当于copyWithin(3, 0, 5),其中length - target = 2end - start = 5,移动次数为两者较小值2

在这里插入图片描述

  另外一种情况由endstart决定。

[1, 2, 3, 4, 5].copyWithin(0, 3, 4) // [4, 2, 3, 4, 5]             

  length - target = 5end - start = 1,移动次数为两者较小值1

在这里插入图片描述

  故移动次数为Math.min(length - target, end - start)

类数组

  copyWithin对于类数组也是适用的。

[].copyWithin.call({length: 5, 3: 1}, 0, 3) // {0: 1, 3: 1, length: 5}

  对象仅含有此属性时,才复制到对应位置。

if (start in this) {
  this[target] = this[start]
}

  注意只能用in操作符判断,不能用this[start] !== undefined来判断,原因在于可能属性值就是undefined

const foo = {}
const bar = { key: undefined }

foo.key // undefined
'key' in foo // false

bar.key // undefined
'key' in bar // true

倒序移动

  以上代码运行如下示例,输出[1, 2, 3, 3, 3, 6],并不是正确的结果。

[1, 2, 3, 4, 5, 6].copyWithin(3, 2, 4) // [1, 2, 3, 3, 4, 6]

  我们将startend固定为24,看看不同target值时的情况。

在这里插入图片描述

startendcounttargetstart < targettarget < start + count输出结果正确结果一致
2420[3, 4, 3, 4, 5, 6][3, 4, 3, 4, 5, 6]
2421[1, 3, 4, 4, 5, 6][1, 3, 4, 4, 5, 6]
2422[1, 2, 3, 4, 5, 6][1, 2, 3, 4, 5, 6]
2423[1, 2, 3, 3, 3, 6][1, 2, 3, 3, 4, 6]
2424[1, 2, 3, 4, 3, 4][1, 2, 3, 4, 3, 4]
2425[1, 2, 3, 4, 5, 3][1, 2, 3, 4, 5, 3]

  可以发现,唯独运行copyWithin(3, 2, 4)时结果错误。

  原因在于移动过程中前面的元素会覆盖后面的元素。

在这里插入图片描述

  倒序移动问题将得到解决。

在这里插入图片描述

  注意仅有start < targettarget < start + count都满足时,才倒序移动,剩余情况还是正常移动。另外target应该从target + count - 1递减,例如以上target应该从索引为43 + 2 - 1)的位置开始,start也同理。

if (start < target && target < start + count) {
  inc = -1
  target += count - 1
  start += count - 1
}

ES5 兼容

function toAbsoluteIndex(target, len) {
  return target < 0 ? len + target : Math.min(target, len)
}

Array.prototype.copyWithin = function (target, start, end) {
  var len = this.length
  target = toAbsoluteIndex(target, len)
  start = toAbsoluteIndex(start || 0, len)
  end = end === undefined ? len : toAbsoluteIndex(end, len)
  var count = Math.min(len - target, end - start)
  var inc = 1

  if (start < target && target < start + count) {
    inc = -1
    target += count - 1
    start += count - 1
  }

  while (count--) {
    if (start in this) {
      this[target] = this[start]
    }

    target += inc
    start += inc
  }

  return this
}

🎉 写在最后

🍻伙伴们,如果你已经看到了这里,觉得这篇文章有帮助到你的话不妨点赞👍或 Star ✨支持一下哦!

手动码字,如有错误,欢迎在评论区指正💬~

你的支持就是我更新的最大动力💪~

GitHub / GiteeGitHub Pages掘金CSDN 同步更新,欢迎关注😉~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DonV

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值