Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

第 158 题:如何模拟实现 Array.prototype.splice #384

Open
yygmind opened this issue May 19, 2020 · 45 comments
Open

第 158 题:如何模拟实现 Array.prototype.splice #384

yygmind opened this issue May 19, 2020 · 45 comments

Comments

@yygmind
Copy link
Contributor

yygmind commented May 19, 2020

No description provided.

@kt3721
Copy link

kt3721 commented May 19, 2020

Array.prototype._splice = function (start, deleteCount, ...addList) {
        if (start < 0) {
            if (Math.abs(start) > this.length) {
                start = 0
            } else {
                start += this.length
            }
        }

        if (typeof deleteCount === 'undefined') {
            deleteCount = this.length - start
        }

        const removeList =  this.slice(start, start + deleteCount)

        const right = this.slice(start + deleteCount)

        let addIndex = start
        addList.concat(right).forEach(item => {
            this[addIndex] = item
            addIndex++
        })
        this.length = addIndex

        return removeList
    }

@hexuan-aurora
Copy link

Array.prototype.splice = function(start, deleteCount, ...items) {
    let deletedItems = [];

    if (Object.is(arguments.length, 0)) return deletedItems;

    const length = this.length;

    let actualStart = +start || 0;
    actualStart =  actualStart >= 0 ? Math.min(actualStart, length) : Math.max(length + actualStart, 0); // 防止 start 越界

    let actualDeleteCount;
    if (Object.is(arguments.length, 1)) {
        actualDeleteCount = length - actualStart; // 未传 deleteCount 时默认删除 start 右侧所有元素
    } else {
        actualDeleteCount = Math.min(Math.max(+deleteCount, 0), length - actualStart); // 防止 deleteCount 大于 start 右侧所有元素长度
    }

    deletedItems = this.slice(actualStart, actualStart + actualDeleteCount); // 待删除元素

    const resetItems = this.slice(actualStart + actualDeleteCount); // 右侧剩余元素
    [...items, ...resetItems].forEach(item => this[actualStart++]=item);  // 将待添加元素与右侧剩余元素添加至原数组中
    
    this.length = actualStart;

    return deletedItems;
}

@zitup

This comment has been minimized.

@yaoqifa
Copy link

yaoqifa commented May 19, 2020

Array.prototype.mySplice = function (start, count, ...args) {
const len = this.length
let _start = start
let res = []
let thisArr = []
function setThis(that, arr) {
arr.forEach((v, index) =>that[index] = v)
that.length = arr.length
}
if (start < 0) {
_start = len + start
_start = _start < 0 ? 0 : _start
}
if (start > len) {
_start = len
}
if (count === undefined) {
res = this.slice(_start)
setThis(this, this.slice(0, _start))
return res
}
res = this.slice(_start, _start + count)
const left = this.slice(0, _start)
const right = this.slice(_start + count)
setThis(this, left.concat(args, right))
return res
}

@weiweixuan
Copy link

// splice
      let arr1 = [1, 3, 5, 7, 9];
      let arr2 = [1, 3, 5, 7, 9];
      /*
          一个参数表示删除后面所有元素
          两个参数表示走a开始删b个元素
          两个以上表示走a开始删b个元素,再这个位置添加元素
        */
      Array.prototype.mySplice = function (index, delCount, ...args) {
        // 判断this
        if (this === null || this === undefined) {
          throw new TypeError(
            "Cannot read property 'map' of null or undefined"
          );
        }
        let O = Object(this),
          len = O.length;
        // 第一个参数,不存在 (返回空数组)
        if (index === undefined) {
          return [];
        }
        index = Number(index);
        // 第一个参数不是数字  (全删除)
        if (isNaN(index)) {
          return delArray(O, 0);
        }
        // index若为负值或者超过length
        index = changeIndex(index, len);

        // 第二个参数没有 (后面的全删除)
        if (delCount === undefined) {
          return delArray(O, index);
        }
        // 第二个参数不是数字 (返回空数组)
        if (isNaN(delCount)) {
          return [];
        } else {
          // 第三个参数存在
          if (Array.isArray(args)) {
            return add(O, index, delCount, args);
          }
          // 不存在
          // 删除数组
          return delArray(O, index, delCount);
        }
      };
      function changeIndex(index, len) {
        // 若为负值
        while (index < 0) {
          index += len;
        }
        // 若为超过len的值
        if (index >= len) {
          index = len;
        }
        return index;
      }
      // 添加元素
      function add(arr, index, count, temp) {
        // 先删除
        let a = delArray(arr, index, count);
        // 添加元素
        for (let i = 0; i < temp.length; i++) {
          // 外层循环添加次数
          for (let j = arr.length; j > index + i; j--) {
            arr[j] = arr[j - 1];
          }
          arr[index + i] = temp[i];
        }
        return a;
      }
      // 删除元素
      function delArray(arr, index, count = arr.length) {
        let temp = [],
          len = arr.length;
        //判断有效的count
        count = len - index >= count ? count : len - index;
        for (let i = 0; i < count; i++) {
          let item = arr[index + i];
          temp.push(item);
        }
        while (count) {
          count--;
          for (let j = index; j < arr.length - 1; j++) {
            arr[j] = arr[j + 1];
          }
          let len_ = arr.length - 1;
          delete arr[len_];
          arr.length = len_;
        }
        return temp;
      }
      let res1 = arr1.mySplice(1, 1, 111, 222, 333);
      let res2 = arr2.splice(1, 1, 111, 222, 333);
      console.log(res1, arr1, res2, arr2);

@wulichenyang
Copy link

前端的原始API还有没写的吗?

@listentolife
Copy link

Array.prototype.splice = function (start, deleteCount, ...args) {
  // 处理start值
  if (start < 0) {
    if (Math.abs(start) > this.length - 1) {
      start = 0
    } else {
      start += this.length
    }
  }
  // 处理deleteCount值
  deleteCount = typeof deleteCount !== 'undefined' ? deleteCount : this.length
  // 处理args值
  args = args.length ? args : []
  // 处理特殊情况
  if (start > this.length - 1) {
    this.concat(args)
    return []
  }
  /**
   * 思路
   * 先把原数组值取出,原数组清空
   * 先入栈不需要处理的数组前部分元素
   * 然后把需要加入的args
   * 最后入栈数组后部分元素
   * 返回中间删掉的元素组成的数组
   */
  let arr = [...this]
  this.length = 0 // 清空
  // 先入栈前部分元素
  let i = 0
  while (i < start) {
    this.push(arr.shift())
    i++
  }
  // 入栈args
  args.forEach(item => this.push(item))
  // 入栈后部分元素
  arr.forEach((item, index) => {
    if (index >= deleteCount) {
      this.push(item)
      delete arr[index]
    }
  })
  // 返回删除部分
  return arr
}

@1eeing
Copy link

1eeing commented May 26, 2020

//@ts-ignore
Array.prototype._splice = function (index: number, count: number, ...args: any[]) {
  const deletes = [];
  let res = [];
  let pushIndex;
  for(let i = 0; i < this.length; i++){
      if(i === index && args.length){
          pushIndex = i;
      }
      if(i >= index && i < (index+count)){
          deletes.push(this[i]);
          continue;
      }
      res.push(this[i]);
  }
  if(pushIndex !== void 0){
      const left = res.slice(0, pushIndex);
      const right = res.slice(pushIndex, res.length);
      res = [...left, ...args, ...right];
  }
  this.length = 0;
  this.push(...res);
  return deletes;
}

@sheepshine
Copy link

Array.prototype.spliceMy = function (startIndex, endIndex, ...item) {
    if (startIndex < 0) {
        startIndex = this.length + startIndex
        endIndex = this.length + startIndex + endIndex
    } else {
        endIndex = startIndex + endIndex
    }
    let arrStart = this.slice(0, startIndex)
    let arrEnd = this.slice(endIndex, this.length)
    console.log(arrStart, arrEnd)
    let returnArr = this.slice(startIndex, endIndex)
    let newArr = arrStart.concat(item).concat(arrEnd)
    for (let i = 0; i < newArr.length; i++) {
        this[i] = newArr[i];
    }
    this.length = newArr.length
    return returnArr
}

@fengqinglingyu
Copy link

/**
 * @param {number} idx 开始删除的索引
 * @param {number} deleteCount 需要删除的数目
 * @param {any[]} insertItems 需要插入项
 * @returns {any[]} 被删的数组项的数组
 */
Array.prototype.mySplice = function (idx, deleteCount) {
  var arr = this;
  var length = arr.length;
  var insertItems = [].slice.call(arguments, 2);
  deleteCount =
    typeof deleteCount !== 'undefined' && deleteCount <= length - idx
      ? deleteCount
      : length - idx;
  var res = [];
  while (deleteCount) {
    deleteCount--;
    if (idx in arr) {
      res.push(arr[idx]);
    }
    for (var i = idx; i < arr.length - 1; i++) {
      arr[i] = arr[i + 1];
    }
    arr.length = arr.length - 1;
  }
  for (var j = 0; j < insertItems.length; j++) {
    arr.push(insertItems[j]);
  }
  return res;
};

写了一个TS的,编译了下

@ZangYuSong
Copy link

ZangYuSong commented Jun 8, 2020

有几点需要注意的:

1、第一个参数,开始下标
2、第二个参数,删除个数
3、从第三个开始往后都是插入的数据

4、操作的都是原数组,也就是改变的是原数组
5、返回一个被删除的数据的新数组

下边这个是我老早之前写的,参考了 chrome 的实现方式

Array.prototype._splice = function () {
  if (arguments.length === 0) return [];
  var arg_len = arguments.length,
    array_len = this.length,
    index = parseInt(arguments[0]) ? parseInt(arguments[0]) : 0,
    num = parseInt(arguments[1])
      ? parseInt(arguments[1]) < 0
        ? 0
        : parseInt(arguments[1])
      : 0;
  // 起始下标
  if (index < 0) {
    index += array_len;
    if (index < 0) {
      index = 0;
    }
  }
  // 删除个数
  if (index + num > array_len) {
    num = array_len - index;
  }
  // 删除
  var new_array = [];
  if (num > 0) {
    for (var i = 0, k = 0; i < array_len; i++) {
      if (i !== index) {
        this[k++] = this[i];
      } else {
        for (var j = 0; j < num; j++) {
          new_array[j] = this[i++];
        }
        i--;
      }
    }
  }
  // 插入数据
  this.length = array_len - num + (arg_len < 2 ? 0 : arg_len - 2);
  if (arg_len === 2) {
    return new_array;
  }
  array_len -= num;
  for (i = this.length - 1; i >= 0; i--) {
    if (i !== index + arg_len - 3) {
      this[i] = this[--array_len];
    } else {
      for (j = arg_len - 1; j > 1; j--, i--) {
        this[i] = arguments[j];
      }
      i++;
    }
  }
  return new_array;
};

@czz362100
Copy link

czz362100 commented Jun 9, 2020

/***

  • index: 删除的起始下标
  • num:删除个数
  • addlist: 新增的元素
  • returnItem :返回已删除元素
    */
Array.prototype._slice = function(index, num, ...addList) {
    let newArr = []
    let returnItem = []
    while(num > 0) {
        // 起始下标有可能传入负数
        if (index < 0) {
            index += this.length
        }
        // 删除当前项
        returnItem.push(this[index])
        delete this[index]
        index++
        num--
    }
    // 将老数组赋予新数组
    for(const item of arr) {
        if(item) newArr.push(item)
    }
    let length = newArr.length
    for(var i = 0; i< length;i++) {
        this[i] = newArr[i]
    }
    this.length = length
    // 新增元素
    if(addList && addList.length > 0) {
        for(const item of addList) {
            this.push(item)
        }
    }
    return returnItem
}

@GuoYiJi
Copy link

GuoYiJi commented Jun 12, 2020

(function () {

  const del = (arr, index, len) => {
    if (index < 0) {
      index = arr.length - Math.abs(index);
    }
    let i = index + len;
    let result = [];


    let count = len;
    let offset = index;
    while (count--) {
      result.push(arr[offset++]);
    }

    while (i < arr.length) {
      arr[i - len] = arr[i];
      i++;
    }

    arr.length = arr.length - len;
    return result;

  }

  const insert = (arr, index, items) => {
    // arr.length = arr.length + items.length;

    let i = arr.length - 1;

    while (i >= index) {
      arr[i + items.length] = arr[i];
      i--;
    }
    i = 0;
    while (i < items.length) {
      arr[i + index] = items[i];
      i++
    }

  }
  
  Array.prototype._splice = function _splice(index, deleteCount, ...rest) {

    let arr = this;
    let removed = [];
  
    // 只有一个元素
    if (deleteCount === undefined) {
      removed = del(arr, index, arr.length - Math.abs(index));
    } else {
      removed = del(arr, index, deleteCount);
      if (rest.length) {
        insert(arr, index, rest);
      }
    }
  
  
    return removed;
  }
  var myFish = ["angel", "clown", "mandarin", "sturgeon"];
  var removed = myFish._splice(2, 0, "drum");
  console.log(myFish, removed)
  
  // 运算后的 myFish: ["angel", "clown", "drum", "mandarin", "sturgeon"]
  // 被删除的元素: [], 没有元素被删除
  
  var myFish = ['angel', 'clown', 'mandarin', 'sturgeon'];
  var removed = myFish._splice(2, 0, 'drum', 'guitar');
  console.log(myFish, removed)
  
  // 运算后的 myFish: ["angel", "clown", "drum", "guitar", "mandarin", "sturgeon"]
  // 被删除的元素: [], 没有元素被删除
  
  var myFish = ['angel', 'clown', 'drum', 'mandarin', 'sturgeon'];
  var removed = myFish._splice(3, 1);
  console.log(myFish, removed)
  
  // 运算后的 myFish: ["angel", "clown", "drum", "sturgeon"]
  // 被删除的元素: ["mandarin"]

  var myFish = ['angel', 'clown', 'drum', 'sturgeon'];
  var removed = myFish._splice(2, 1, "trumpet");
  console.log(myFish, removed)

  // 运算后的 myFish: ["angel", "clown", "trumpet", "sturgeon"]
  // 被删除的元素: ["drum"]

  var myFish = ['angel', 'clown', 'trumpet', 'sturgeon'];
  var removed = myFish._splice(0, 2, 'parrot', 'anemone', 'blue');
  console.log(myFish, removed)

  // 运算后的 myFish: ["parrot", "anemone", "blue", "trumpet", "sturgeon"]
  // 被删除的元素: ["angel", "clown"]

  var myFish = ['parrot', 'anemone', 'blue', 'trumpet', 'sturgeon'];
  var removed = myFish._splice(myFish.length - 3, 2);
  console.log(myFish, removed)

  // 运算后的 myFish: ["parrot", "anemone", "sturgeon"]
  // 被删除的元素: ["blue", "trumpet"]

  var myFish = ['angel', 'clown', 'mandarin', 'sturgeon'];
  var removed = myFish._splice(-2, 1);
  console.log(myFish, removed)

  // 运算后的 myFish: ["angel", "clown", "sturgeon"]
  // 被删除的元素: ["mandarin"]

  var myFish = ['angel', 'clown', 'mandarin', 'sturgeon'];
  var removed = myFish._splice(2);
  console.log(myFish, removed)

  // 运算后的 myFish: ["angel", "clown"]
  // 被删除的元素: ["mandarin", "sturgeon"]

})()

@lvwxx
Copy link

lvwxx commented Jun 15, 2020

Array.prototype.splice = function(start, delCount, ...items) {
  let arr = this
  let delArr = []
  let end = start
  const len = arr.length
  const startArr = arr.slice(0, start)
  if (delCount && delCount > 0) {
    end += delCount
    delArr = delArr.concat(arr.slice(start, end))
  }
  const endArr = arr.slice(end, len+1)
  const newArr = startArr.concat(items).concat(endArr)
  newArr.forEach((item,index) => {
    this[index] = item
  })
  this.length = newArr.length
  return delArr
}

@NathanHan1
Copy link

Array.prototype.mySplice = function(start, deleteCount, ...items) {
        const preLen = this.length + items.length
        const rightArr = items.concat(this.slice(start + deleteCount))
        let i = start
        while(rightArr.length) {
          this[i] = rightArr.shift()
          i++
        }
        this.length = preLen - deleteCount
      }

@NathanHan1
Copy link

Array.prototype.mySplice = function(start, deleteCount, ...items) {
        const preLen = this.length + items.length
        const rightArr = items.concat(this.slice(start + deleteCount))
        let i = start
        while(rightArr.length) {
          this[i] = rightArr.shift()
          i++
        }
        this.length = preLen - deleteCount
      }

最短代码数😝

@yangchaojie456
Copy link

各位大佬指点一下

Array.prototype.splice = function (index, howmany, ...items) {
    items = items || []

    var arr = this
    var len = arr.length
    var deleteItems = []
    if (howmany == items.length) {
        for (var i = index; i < index + howmany; i++) {
            deleteItems.push(arr[i])
            arr[i] = items[i - index]
        }
    } else if (howmany > items.length) {
        var i = index
        var temp = howmany
        while (howmany) {
            deleteItems.push(arr[i])
            arr[i] = items[i - index]
            i++
            howmany--
        }
        for (var i = index + items.length; i < len; i++) {
            arr[i] = arr[i + temp - items.length]
        }
        arr.length = len - (temp - items.length)

    } else if (howmany < items.length) {
        var step = items.length - howmany
        var i = len + step - 1
        while (i >= index) {

            if (i < items.length + index) {
                arr[i] = items[i - index]
            } else {
                arr[i] = arr[i - step]
            }
            i--
        }


    }
    return deleteItems
}

var arr = [0, 1, 2, 3, 4, 5, 6]
arr.splice(3, 3, ...[7, 8, 9])
console.log(arr)

@xueshuai
Copy link

xueshuai commented Sep 1, 2020

index, delCount, ...args

大佬,你这个好像有点问题啊,这块就有点问题,第二个参数没有,应该从第一个参数开始往后删除,不应该直接全删除吧

// 第二个参数没有 (后面的全删除)
if (delCount === undefined) {
    return delArray(O, index);
}

@zhangfytech
Copy link

Array.prototype._splice = function (index, deleteCount, ...items) {
        if (index > this.length || index < 0) {
            console.error("start index should between 0 and self length");
            return;
        }
        var deleteNum = deleteCount >= 0 ? deleteCount : 0;
        var preList = [], suffixList = [], replaceList = [];
        for (let i = 0; i < this.length; i++) {
            if (i < index) {
                preList.push(this[i]);
            } else {
                suffixList.push(this[i]);
            }
        }

        while (deleteNum--) {
            replaceList.push(suffixList[0]);
            suffixList.shift();
            if (!deleteNum) break
        }

        preList = preList.concat(items).concat(suffixList);
        preList.forEach((v, i) => {
            this[i] = v
        });

        return replaceList;
    };

@caoyi5225
Copy link

/**
 * Array.prototype.splice polyfill
 * 时间复杂度: o(1n) 一次遍历
 * 空间复杂度: o(1n) 原地算法
 */
Array.prototype.splice = function(start, deleteCount, ...items) {
  if (typeof start !== 'number' || isNaN(start)) {
    throw new TypeError('start must be a number');
  }
  if (start < 0) {
    start = this.length - start;
  }

  if (deleteCount !== undefined &&
    (typeof deleteCount !== 'number' || isNaN(deleteCount) )
  ) {
    throw new TypeError('deleteCount must be a number');
  }
  if (deleteCount === undefined || deleteCount > this.length - start ) {
    deleteCount = this.length - start;
  }

  const res = [];
  // 计算移动方向, 不同的移动方向操作不同
  // 左移: 从左往右遍历
  // 右移: 从右往左移动
  let moveVector = items.length - deleteCount,
    // 待插入的元素个数
    pendingIntert = items.length;
    if (moveVector <= 0) {
      for (let i = start; i < this.length; i++) {
        // 记录删除的元素
        if (i - start < deleteCount) {
          res.push(this[i]);
        }
        if (i < this.length + moveVector) {
          // 如果有未插入的元素, 先插入
          if (pendingIntert > 0) {
            this[i] = items[items.length - pendingIntert--];
          } else {
            // 如果没有未插入元素, 左移
            this[i] = this[i - moveVector];
          }
        }
      }
      // 缩减数组长度
      this.length = this.length + moveVector;
    } else {
      for (let i = this.length + moveVector - 1; i >= start; i--) {
        // 记录删除的元素
        if (i - start < deleteCount) {
          res.unshift(this[i]);
        }
        if (i < start + items.length) {
          // 开始插入元素
          this[i] = items[--pendingIntert];
        } else {
          // 右移
          this[i] = this[i - moveVector];
        }
      }
    }
  return res;
}

const testArr = [1, 2, 3];
console.log('res', testArr.splice(0, 1, 4, 5, 6, 7));
console.log(testArr);

@slogeor
Copy link

slogeor commented Sep 16, 2020

Array.prototype.mySplice = function(start, deleteCount, ...items) {
        const preLen = this.length + items.length
        const rightArr = items.concat(this.slice(start + deleteCount))
        let i = start
        while(rightArr.length) {
          this[i] = rightArr.shift()
          i++
        }
        this.length = preLen - deleteCount
      }

最短代码数😝

没有看到返回值

@jiangkuan2018
Copy link

jiangkuan2018 commented Sep 21, 2020

Array.prototype.splice2 = function(start, delCount, ...args) {
  let firstPart = []
  let secondPart = []
  let res = []
  start = start > 0 ? start : (this.length + start)
  delCount = delCount || this.length - start
  for (let i = 0; i < this.length; i++) {
    if (i < start) {
      firstPart.push(this[i])
    } else {
      secondPart.push(this[i])
    }
  }
  for (let i = 0; i < delCount; i++) {
    res.push(secondPart[i])
    delete secondPart[i]
  }
  const newlist = firstPart.concat(args).concat(secondPart.filter(item => item))
  newlist.forEach((item, index) => {
    this[index] = item
  })
  this.length = newlist.length
  return res
}

let arr1 = ['jk', 26, 'chrome', 'mac', 'win']
let arr2 = ['jk', 26, 'chrome', 'mac', 'win']
console.log(arr1.splice2(-2, 2), arr1)
console.log(arr2.splice(-2, 2), arr2)

@chasegirls
Copy link

Array.prototype._splice = function (start, deleteCount, ...addList) {
if (start < 0) {
if (Math.abs(start) > this.length) {
start = 0
} else {
start += this.length
}
}
// 判断deleteCount 是否大于0
deleteCount = deleteCount > 0 ? deleteCount : 0
// 删除了的数组
const removeList = this.slice(start, start + deleteCount)
// 取出未删除完的
const right = this.slice(start + deleteCount)
//
let addIndex = start
addList.concat(right).forEach(item => {
this[addIndex] = item
addIndex++
})
this.length = addIndex

  return removeList
}

@cuizaiyong
Copy link

Array.prototype.splice = function (start = 0, number = 0, value) {
  const arr = [...this];
  const delArr = [];
  const range = start + number;
  this.length = 0;
  for (const [index, item] of arr.entries()) {
    if (index > range) {
      this.push(item);
    } else if (index === range) {
      if (value) {
        this.push(value);
      }
      this.push(item);
    } else {
      if (index < start) {
        this.push(item);
      } else {
        delArr.push(item);
      }
    }
  }
  return delArr;
};

@vince-fly
Copy link

Object.defineProperty(Array.prototype, 'vsplice', {
    value: function (start, delCount, ...args) {
        if (this === null) {
            throw TypeError('对象不可为空');
        }

        var o = Object(this);
        if (arguments.length < 1) {
            throw TypeError('开始位置参数不能为空');
        }
        var len = o.length >>> 0;
        var argsLen = arguments.length;
        var k = 0;
        while (k < len && !(k in o)) {
            k++;
        }
        if (k >= len && argsLen < 3) {
            return [];
        }

        if (start > len) {
            return o;
        }
        var realStart = start;

        if (start < 0) {
            realStart = len + start;
        }
        if (realStart < 0) {
            realStart = 0;
        }

        var realCount = delCount;
        if (argsLen === 1) {
            realCount = len - realStart;
        }
        if (argsLen === 2 && delCount <= 0) {
            return o;
        }
        var other = new Array(realCount);
        if (realCount > 0) {
            k = realStart;            
            var otherK = 0;
            while (k < len && realCount > 0) {
                other[otherK++] = o[k];
                delete o[k];
                //o.length--;
                k++;
                realCount--;
            }
            if(argsLen<3){
                return other;
            }
            
        }

        len = o.length >>> 0;

        var inserts = Array.prototype.slice.call(arguments, 2);

        for (var i = 0; i < inserts.length; i++) {
            if (len === 0) {
                o[realStart++] = inserts[i];
            } else {
                var temp = o[realStart];
                o[realStart] = inserts[i];
                if(temp!== undefined){
                    o[1 + realStart] = temp;
                }                
                realStart ++;
            }
        }

        return other;
    }
});

@hcc0007
Copy link

hcc0007 commented Nov 6, 2020

思路:
砍左中右三个部分,然后分别处理。

const arr = [1, 2, 12, 32, 43]
const after = arr.splice(-1, -2,33, 4);
console.log('答案 ---', arr, after);

const arr2 = [1, 2, 12, 32, 43];
function splice(list, start, deleteNum, ...addList) {
  const startIndex = start > 0 ? start : list.length - Math.abs(start);
  const endIndex = deleteNum > 0 ? startIndex + deleteNum : undefined;
  let left = [];
  let splice = [];
  let right = [].concat(addList);
  
  list.forEach((item, index) => {
    if (index < startIndex) left.push(item);
    if (index >= startIndex && endIndex === undefined) {
      right.push(item);
      return;
    }
    if (index >= startIndex && index < endIndex) splice.push(item);
    if (index >= endIndex) right.push(item);
  })
  list.length = 0;
  list.push(...left, ...right);
  return splice;
}

const newArr = splice(arr2, -1, -2,33, 4);
console.log('结果 ---', arr2, newArr);

@hcc0007
Copy link

hcc0007 commented Nov 6, 2020

Array.prototype.mySplice = function(start, deleteCount, ...items) {
        const preLen = this.length + items.length
        const rightArr = items.concat(this.slice(start + deleteCount))
        let i = start
        while(rightArr.length) {
          this[i] = rightArr.shift()
          i++
        }
        this.length = preLen - deleteCount
      }

最短代码数😝

大佬 您这个是真的秀了!!秀的我眼花缭乱

@JianJroh
Copy link

100% mock Array.prototype.splice

Array.prototype._splice = function(index, cutNum, ...args) {
	const arr = this;
	const leftArr = arguments.length === 0 ? [] : arr.slice(0, index);
	const rightArr = arguments.length === 1 ? [] : arr.slice(index + (cutNum || 0));
	const changeArr = [...leftArr, ...args, ...rightArr];
	const result = arguments.length === 1 ? arr.slice(index) : arr.slice(index, index + cutNum)
	changeArr.forEach((val,index) => this[index] = val);	// change
	this.length = changeArr.length;
	return result;
}
//  test
var arr1 = [1,2,3,4,5,6,7];
var arr2 = [1,2,3,4,5,6,7];
console.log(arr1.splice(1,3,'a','b'));
console.log(arr1);
console.log(arr2._splice(1,3,'a','b'));
console.log(arr2);

@Luz-Liu
Copy link

Luz-Liu commented Feb 20, 2021

Array.prototype.splice = function (start, deleteCount, ...items) {
	if (start < 0) {
		start += this.length;
	}
	if (start < 0) start = 0;
	if (deleteCount == undefined) {
		deleteCount = this.length - start;
	} else if (deleteCount < 0) {
		deleteCount = 0;
	}
	const left = [].slice.call(this, 0, start);
	const deleted = [].slice.call(this, start, start + deleteCount);
	const right = [].slice.call(this, start + deleteCount);

	this.length = 0;
	this.push(...left, ...items, ...right);
	return deleted;
};

@yinhaiying
Copy link

Array.prototype.splice = function(start,deleteCount,...rest){
    let arr  = this;
    let deleteArr = [];
    // 如果第二个参数没有,说明从start删到最后
    if(deleteCount === undefined){
        deleteArr = arr.slice(start);
    }
    if(deleteCount >= 0){
        deleteArr = arr.slice(start, start + deleteCount);
        arr = arr.slice(0, start).concat(rest).concat(arr.slice(start + deleteCount))
    }
    // 修改原来数组
    arr.forEach((item,index) => this[index] = item);
    this.length = arr.length;
    return deleteArr;
}


@zhangfangbiao
Copy link

Array.prototype.splice2 = function(start, count, ...addList) {
    if (start < 0) {
        if (Math.abs(start) > this.length) {
            start = 0
        } else {
            start = this.length + start
        }
    }
    if (typeof count !== 'number') {
        count = this.length - start
    } else {
        if (count < 0) {
            count = 0
        }
    }
    let delList = this.slice(start, start + count)
    let right = this.slice(start + count, this.length)
    this.length = start
    this.push(...(addList.concat(right)))
    return delList
}

@qzruncode
Copy link

Array.prototype.spliceLike = function(start, num, ...params) {
    return [...this.slice(0, start), ...params, ...this.slice(start + num)]
}

@haipingzi
Copy link

haipingzi commented Apr 26, 2021

    Array.prototype._splice = function (start, count, ...replaceEl) {
      if (typeof start !== "number") throw new Error("start not a number");
      if (typeof count !== "number") throw new Error("count not a number");
      start = start < 0 ? Math.max(start + this.length, 0) : start; // 开始值为负数要加上数组长度且不能小于零;
      Math.max(0, count); // 删除数量大于等于0;
      const delArr = this.slice(start, start + count);
      const resArr = [
        ...this.slice(0, start),
        ...replaceEl,
        ...this.slice(start + count),
      ];
      delArr.forEach((item, index) => {
        delete this[index];
      });
      resArr.forEach((item, index) => {
        this[index] = item;
      });
     this.length = resArr.length;
      return delArr;
    };

@haipingzi
Copy link

Array.prototype.splice2 = function(start, count, ...addList) {
    if (start < 0) {
        if (Math.abs(start) > this.length) {
            start = 0
        } else {
            start = this.length + start
        }
    }
    if (typeof count !== 'number') {
        count = this.length - start
    } else {
        if (count < 0) {
            count = 0
        }
    }
    let delList = this.slice(start, start + count)
    let right = this.slice(start + count, this.length)
    this.length = start
    this.push(...(addList.concat(right)))
    return delList
}

const arr1 = [1, 2, 3, 4, 5];
const arr2 = [1, 2, 3, 4, 5];
arr1.splice2(100, 1, [1, 2])
arr2.splice(100, 1, [1, 2])
console.log(arr1)
console.log(arr2)
//大于数组长度就不正确了

@haipingzi
Copy link

Array.prototype._splice = function (start, deleteCount, ...addList) {
        if (start < 0) {
            if (Math.abs(start) > this.length) {
                start = 0
            } else {
                start += this.length
            }
        }

        if (typeof deleteCount === 'undefined') {
            deleteCount = this.length - start
        }

        const removeList =  this.slice(start, start + deleteCount)

        const right = this.slice(start + deleteCount)

        let addIndex = start
        addList.concat(right).forEach(item => {
            this[addIndex] = item
            addIndex++
        })
        this.length = addIndex

        return removeList
    }

sart 大于数组长度就不对了
const arr1 = [1, 2, 3, 4, 5];
const arr2 = [1, 2, 3, 4, 5];
arr1._splice(100, 1, [1, 2])
arr2.splice(100, 1, [1, 2])
console.log(arr1) //  [1, 2, 3, 4, 5, empty × 95, Array(2)]
console.log(arr2) // [1, 2, 3, 4, 5, Array(2)]

Array.prototype._splice = function (start, deleteCount, ...addList) {
        if (start < 0) {
            if (Math.abs(start) > this.length) {
                start = 0
            } else {
                start += this.length
            }
        }

        if (typeof deleteCount === 'undefined') {
            deleteCount = this.length - start
        }

        const removeList =  this.slice(start, start + deleteCount)

        const right = this.slice(start + deleteCount)

        let addIndex = start
        addList.concat(right).forEach(item => {
            this[addIndex] = item
            addIndex++
        })
        this.length = addIndex

        return removeList
    }

start大于数组长度就不对了

@z1948296027
Copy link

z1948296027 commented May 15, 2021

Array.prototype.splice = function(index, num, ...rest) {
    let context = this
    let removeList = []
    //index为负值
    if (index < 0) {
        index = index + context.length
    }
    //num存在
    if(num != null) {
        if (num !== 0) {
            //查找要删除的元素
            for (let i = index; i < index + num; i++) {
                removeList.push(context[i])
            }
            //移除要移除的元素
            const conLength = context.length
            for (let i = index + num; i < conLength; i++) {
                context[i - num] = context[i]
            }
            context.length = conLength - num
        }
        //添加要添加的元素
        if (rest.length > 0) {
            const restLength = rest.length
            const conLength = context.length
            for(let i = conLength - 1; i >= index; i--) {
                context[i+restLength] = context[i]
            }
            
            let count = 0
            for(let i = index; i < index+restLength; i++) {
                context[i] = rest[count]
                count++
            }
        }
    } else {
        //查找要删除的元素
        const conLength = context.length
        for (let i = index; i < conLength; i++) {
            removeList.push(context[i])
        }
        context.length = index
    }
    return removeList
}
var myFish = ['angel', 'clown', 'mandarin', 'sturgeon'];
var removed = myFish.splice(2, 0, 'drum', 'guitar');

console.log(myFish)
console.log(removed)
//应该把数组第index位左移或右移n位抽象成函数,看起来应该就清楚多了

@poppydani
Copy link

Array.prototype._splice = function (start, delCount, ...addItems) {
  const arr = this;
  const res = [];
  const left = arr.slice(0, start);
  const right = arr.slice(start + delCount)
  const remove = arr.slice(start, start + delCount); // 被删除的元素

  arr.length = left.length;
  addItems.forEach(item => arr.push(item));
  right.forEach(item => arr.push(item));
  return remove;
}

@Jobs-Chen
Copy link

Array.prototype._splice = function (start, deleteCount, ...addList) {
        if (start < 0) {
            if (Math.abs(start) > this.length) {
                start = 0
            } else {
                start += this.length
            }
        }

        if (typeof deleteCount === 'undefined') {
            deleteCount = this.length - start
        }

        const removeList =  this.slice(start, start + deleteCount)

        const right = this.slice(start + deleteCount)

        let addIndex = start
        addList.concat(right).forEach(item => {
            this[addIndex] = item
            addIndex++
        })
        this.length = addIndex

        return removeList
    }

你这个有问题,当start不小于0却大于数组长度的时候你这个会错误的导致数组长度变大

@listentolife
Copy link

listentolife commented May 12, 2022 via email

@Jobs-Chen
Copy link

Array.prototype._splice = function(start, delCount, ...addList) {
    // 当起始位置超出了数组的长度,则从数组末尾开始添加内容
    if(start > this.length) {
        start = this.length;
        delCount = 0;
    }
    if(start < 0) {
        // 超出数组长度的话设置为0
        if(Math.abs(start) > this.length) {
            start = 0;
        } else {
            // 如果起始值为负数,则起始位置为数组末尾开始第几位
            start += this.length;
        }
    }
    // 设置删除的长度,没有值的话相当于移除起始位置之后的所有元素
    if(delCount === undefined) {
        delCount = this.length - start;
    }
    // 删除的元素
    const removeList = this.slice(start, start + delCount);
    // 删除元素的右侧数据
    const right = this.slice(start + delCount);

    // 将新加入的数据和右侧剩余的数据合并,然后将数组下标对应位置的元素替换
    let addStart = start;
    addList.concat(right).forEach(item => {
        this[addStart] = item;
        addStart++;
    });
    // 修改数组长度
    this.length = addStart;
    // 返回删除的元素
    return removeList;
}

这里附上MDN对于这个方法的定义Array.prototype.splice()
参数
start​
指定修改的开始位置(从0计数)。如果超出了数组的长度,则从数组末尾开始添加内容;如果是负值,则表示从数组末位开始的第几位(从-1计数,这意味着-n是倒数第n个元素并且等价于array.length-n);如果负数的绝对值大于数组的长度,则表示开始位置为第0位。
deleteCount 可选
整数,表示要移除的数组元素的个数。如果 deleteCount 大于 start 之后的元素的总数,则从 start 后面的元素都将被删除(含第 start 位)。如果 deleteCount 被省略了,或者它的值大于等于array.length - start(也就是说,如果它大于或者等于start之后的所有元素的数量),那么start之后数组的所有元素都会被删除。如果 deleteCount 是 0 或者负数,则不移除元素。这种情况下,至少应添加一个新元素。
item1, item2, ... 可选
要添加进数组的元素,从start 位置开始。如果不指定,则 splice() 将只删除数组元素。
返回值
由被删除的元素组成的一个数组。如果只删除了一个元素,则返回只包含一个元素的数组。如果没有删除元素,则返回空数组。

@lucaslmlok
Copy link

Array.prototype._splice = function (start, deleteCount, ...items) {
  if (start < 0) {
    start += this.length;
  }
  start = Math.max(start, 0);

  if (deleteCount === 'undefined') {
    deleteCount = this.length - start;
  }

  if (start >= this.length) {
    deleteCount = 0;
  }
  deleteCount = Math.max(deleteCount, 0);

  const length = this.length;
  const right = [];
  const deleted = [];

  for (let i = start + deleteCount; i < length; i++) {
    right.unshift(this.pop());
  }

  for (let i = start; i < start + deleteCount; i++) {
    deleted.unshift(this.pop());
  }

  for (let i = 0; i < items.length; i++) {
    this.push(items[i]);
  }

  for (let i = 0; i < right.length; i++) {
    this.push(right[i]);
  }

  return deleted;
};

@Yangfan2016
Copy link

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/splice

start
如果是负数,判断abs 值如果大于 length ,则 start置为 0 否则 start取 length-start
否则(非负数),直接取 start

deleteCount
要删除的个数
如果不指定,或 deleteCount>=length 则将 start 后的 数都删除
如果取值为0或负数,则不进行删除操作
否则删除 包含 start 及之后的 共 deleteCount 个数

item1,item2,...

要插入的元素

@listentolife
Copy link

listentolife commented Aug 18, 2022 via email

@xiaoguoaa
Copy link

Array.prototype._splice = function(index, deleteCount, ...items) {
  if (index < 0) {
    index = this.length + index;
  }
  if (deleteCount === undefined) {
    deleteCount = this.length - index;
  }
  if (deleteCount < 0) {
    deleteCount = 0;
  }
  let res = this.slice(index, index + deleteCount);
  let temp = [...this.slice(0, index), ...items, ...this.slice(index + deleteCount)];
  if (temp.length < this.length) {
    this.length = temp.length;
  }
  for (let i = 0; i < temp.length; i++) {
    this[i] = temp[i];
  }
  return res;
};

@ZegTsai
Copy link

ZegTsai commented Aug 29, 2023

function mySplice(start, deleteNum, ...newItem) {
  // 传参检查与转换
  if (typeof start !== "number" || deleteNum < 0) return [];
  start < 0 && (start = Math.abs(this.length + start));
  typeof deleteNum !== "number" && (deleteNum = this.length - start);

  const removeList = this.slice(start, start + deleteNum),
    newList = [
      ...this.slice(0, start),
      ...newItem,
      ...this.slice(start + deleteNum),
    ];
  this.length += newItem.length - deleteNum;
  let p = 0;
  while (p < this.length) {
    this[p] = newList[p++];
  }
  return removeList;
}

Array.prototype.mySplice = mySplice;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests