100行代码实现数组的splice方法

splice基本了解

在JavaScript中Array提供了许多方法供我们使用,splice是我们经常会使用到的一个方法。

要实现一个splice方法,我们首先看一下 splice 定义 和 用法

定义vs用法:
splice()方法向从数组中添加删除项目,然后返回被删除的项目。

语法
arrayObject.splice(index,howmany,item1,.....,itemX)

参数 描述
index 必需。整数,规定添加/删除项目的位置,使用负数可从数组结尾处规定位置。
howmany 必需。要删除的项目数量。如果设置为 0,则不会删除项目。
item1, …, itemX 可选。向数组添加的新项目。
返回值 描述
Array 包含被删除项目的新数组,如果有的话。

Tips:splice() 方法与 slice() 方法的作用是不同的,splice() 方法会直接对原数组进行修改。

在清楚了splice方法的基本概念后,首先我们试着来实现一个简易版的

  1. 拷贝删除的元素
  2. 移动删除元素后面的元素
  3. 插入新的元素
      //splice
      Array.prototype.splice = function (
        startIndex,
        deleteCount,
        ...addElements
      ) {
        let argumentLen = arguments.length;
        let array = Object(this);
        let len = array.length;
        let deleteArr = new Array(deleteCount);

        //拷贝删除的元素
        sliceDeleteElements(arra, startIndex, deleteCount, deleteArr);
        //移动删除元素后面的元素
        movePostElements(array, startIndex, len, deleteCount, addElements);
        //插入新的元素
        for (let i = 0; i < addElements.length; i++) {
          array[startIndex+i] = addElements[i];
        }
        array.length = len - deleteCount + addElements.length;
        return deleteArr;
      };
复制代码

拷贝删除的元素

    const sliceDeleteElements = (array, startIndex, deleteCount, deleteArr) => {
        for(let i = 0;i<deleteCount;i++){
          let index = startIndex + i
          if(index in array) {
            let current = array[index];
            deleteArr[i] = current;
          }
        }
      }
复制代码

移动删除元素后面的元素

  • 添加的元素和删除的元素个数相等时
  • 添加元素个数大于删除元素时
  • 添加元素个数小于删除元素时
//移动删除元素后面的元素
      //相等时
      const movePostElements = (
        array,
        startIndex,
        len,
        deleteCount,
        addElements
      ) => {
        if (deleteCount === addElements.length) return;
      };
      //小于
      const movePostElements = (
        array,
        startIndex,
        len,
        deleteCount,
        addElements
      ) => {
        if (deleteCount > addElements.length) {
          //删除的元素比新增的元素多,后面的元素向前移动
          //一共需要向前挪动 len - startIndex - deletecount
          for (let i = startIndex + deleteCount; i < len; i++) {
            let formIndex = i;
            //将要挪动的目标位置
            if (formIndex in array) {
              array[toIndex] = array[formIndex];
            } else {
              delete array[toIndex];
            }
          }
        }
        //当前长度为len + addElements - deleteCount
        for (let i = lem - 1; i > len + addElements.length - deleteCount; i--) {
          delete array[i];
        }
      };
      //添加大于删除
      const movePostElements = (
        array,
        startIndex,
        len,
        deleteCount,
        addElements
      ) => {
        if (deleteCount < addElements.length) {
          //删除的元素比新增的元素少,元素整体后前移动
          for(let i = len - 1;i>=startIndex+deleteCount;i--){
            let formIndex  = i;
            //将要挪动的目标位置
            let toIndex = i + (addElements.length -deleteCount);
            if(formIndex in apply){
              array[toIndex] = array[formIndex];
            } else{
              delete array[toIndex]
            }
          }
        }
复制代码

阻止用户传来的不正确的数组边界值(参数)

      // 处理用户传来的不争取的startindex,deletecount。
      const computeStartIndex = (startIndex, len) => {
        if (startIndex < 0) {
          return startIndex + len > 0 ? startIndex + len : 0
        }
        return startIndex >= len ? len : startIndex
      }
      //删除数字处理
      const computeDeleteCount = (startIndex,len,deleteCount,argumentLen) => {
        if(arguments.length === 1){
          return len - startIndex
        }
        if(deleteCount < 0) return 0;
        if(deleteCount > len - deleteCount) return len - startIndex;
        return deleteCount
      }
复制代码

如果数组是只读的或者是不可改变的做处理

  • 密封对象:不可扩展的对象,可以修改属性值,不能添加删除方法和属性 configurable属性值为false
  • 冻结对象:在密封对象的基础上不能修改属性值
    if(Object.isSealed(array) && deleteCount !== addElements.length){
      throw new Error ('this object is a sealed object')
    }else if(Object.isFrozen(array) && (deleteCount > 0 || addElements.length > 0)){
      throw new Error ('this object is a Frozen object')
    }
复制代码

初入前端门,小白菜一枚,记录自己学习路径,希望可以激励自己,希望大家可以轻喷,有不对地方可以指出会及时改成奥!谢谢大家

参考:
三元大神 blog (强烈推荐)

V8数组 splice 源码

w3 School JavaScript plice

MDN
文档 Array Splice

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享