JavaScript不清不楚之copyWithin

Array.prototype.copyWithin

代码均来自:MDN

原数组将被改变,但是数组的长度不会发生变化,IE系列不支持此方法

if (!Array.prototype.copyWithin) {
  Array.prototype.copyWithin = function(target, start/*, end*/) {
    // Steps 1-2.
    //过滤null和undefined  eg: Array.prototype.copyWithin.call(null)
    if (this == null) {
      throw new TypeError('this is null or not defined');
    }

    var O = Object(this);

    // Steps 3-5.
    // >>> 0 的作用(无符号右移):
    // 1.能转换为数值的先转换为数值然后在右移 
    // 2.非数值类型不能转换为数值的返回0 
    // 3.自然数向左取整,负数会转换为正数
    var len = O.length >>> 0;

    // Steps 6-8.
    // >> 0 的作用(有符号右移):
    // 1.能转换为数值的先转换为数值然后在右移 
    // 2.非数值类型不能转换为数值的返回0 
    // 3.自然数向左取整,负数向右取整
    var relativeTarget = target >> 0;
    //扶正target索引,负数绝对值超过len取0,正数超过len取len
    var to = relativeTarget < 0 ?
      Math.max(len + relativeTarget, 0) :
      Math.min(relativeTarget, len);

    // Steps 9-11.
    var relativeStart = start >> 0;

    var from = relativeStart < 0 ?
      Math.max(len + relativeStart, 0) :
      Math.min(relativeStart, len);

    // Steps 12-14.如果没传end取len,传了end就按照上面的规则扶正end
    var end = arguments[2];
    var relativeEnd = end === undefined ? len : end >> 0;

    var final = relativeEnd < 0 ?
      Math.max(len + relativeEnd, 0) :
      Math.min(relativeEnd, len);

    // Step 15.
    var count = Math.min(final - from, len - to);

    // Steps 16-17.
    var direction = 1;
    //from to final count最大为len最小为0 
    //from复制的开始索引, to赋值的开始索引, final复制的结束索引,count
    /**
     * a. from === to
     *     1. from === final    count = 0; return o;
     *     2. from < final      count = final - from; 正常循环,return o;
     *     3. from > final      count < 0; return o;
     * b. from > to
     *     1. from === final    count = 0; return o;
     *     2. from < final      count = final - from; 正常循环,return o;
     *     3. from > final      count < 0; return o;  
     * c. from < to
     *     1. from === final    count = 0; return o;
     *     2. from < final      
     *         i. 如果 final - from <= len - to, count = final - from,
     *         ii. 如果 final - from > len - to, count = len - to, 
     *         按i和ii这种分析方法,不适合恰当,可以画图来示意,就是to始终落在from和final的区间里,
     *         这种情况就需要特殊处理也就是下面的 from < to && to < (from + count)
     *     3. from > final      count < 0; return o; 
     */
    if (from < to && to < (from + count)) {
      direction = -1;
      from += count - 1;
      to += count - 1;
    }

    // Step 18.
    while (count > 0) {
      if (from in O) {
        //这里说明copyWhthin的拷贝是浅拷贝,如果更改了arr里的非原子类型的值,很可能引起多处被修改的问题
        O[to] = O[from];
      } else {
        delete O[to];
      }

      from += direction;
      to += direction;
      count--;
    }

    // Step 19.
    return O;
  };
}
  • copyWithin 函数是设计为通用的,其不要求其 this 值必须是一个数组对象
var obj = {length: 2, a: 1, 1: 2};
Array.prototype.copyWithin.call(obj, 0, "a")
//{1: 2, length: 2, a: 1}

Array.prototype.copyWithin.call({length: 5, a:1, b:2, c:3, d:4, e:5, 1: 1, 2: 2}, 0, "c")
//{1: 1, 2: 2, length: 5, a: 1, b: 2, c: 3, d: 4, e: 5}

猜你喜欢

转载自blog.csdn.net/qq452981462/article/details/80891171