拆解Array.Splice,学习其思路与思想

271 阅读4分钟

在处理业务时,善用Array中的方法,如splice,可以极大地减少我们的工作量并避免冗余的循环代码。通过splice,我们可以方便地对目标数组进行增、删、改操作。

那么有一点我很好奇,就是它本身工作原理是怎么样的呢?

先看看语法:

array.splice(start[, deleteCount[, item1, item2, ...]])

下面我们来拆解它的参数以及返回值:

参数

  • start:指定修改的开始位置(索引)。
  • deleteCount:一个整数,表示要移除的数组元素的个数。
  • item1, item2, ...:要添加进数组的元素,(可选)。如果不指定,则 splice 仅仅删除数组元素。

返回值

由被删除的元素组成的一个数组。如果只删除了一个元素,则返回只包含一个元素的数组。如果没有删除元素,则返回空数组。

知道其本身的参数以及返回值,再来看看它基本做了什么

  1. 检查参数有效性

    • start 必须是一个整数,如果它是负数,则从数组末尾开始计算位置。
    • deleteCount 必须是一个非负整数,如果省略或为大于 array.length - start(即超出范围),则删除从 start 到数组末尾的所有元素。
  2. 计算实际开始索引

    • 如果 start 是负数,则 start = array.length + start
    • 如果 start 大于或等于数组长度,则不执行任何操作,返回一个空数组。
  3. 删除指定数量的元素

    • 从 start 索引开始,删除 deleteCount 个元素。
    • 如果 deleteCount 大于或等于从 start 到数组末尾的元素个数,则删除从 start 到数组末尾的所有元素。
  4. 插入新元素

    • 从 start 索引开始,插入指定的新元素。
  5. 返回被删除的元素

    • 返回一个包含被删除元素的新数组。如果没有删除任何元素,则返回一个空数组。

源码实现

那么接下来我们围绕上面逻辑实现自己的splice

定义一个函数:function customSplice(array, start, deleteCount, ...itemsToAdd) { }

1、处理负数索引

if (start < 0) {  
      start = Math.max(0, array.length + start);  
  }  

2、限制删除的元素数量不超过从start到数组末尾的元素数量

const maxDeleteCount = array.length - start;  
deleteCount = (deleteCount > maxDeleteCount) ? maxDeleteCount : deleteCount;  

3、创建一个新数组来存储被删除的元素

const deletedElements = [];  
  for (let i = 0; i < deleteCount; i++) {  
      deletedElements.push(array[start + i]);  
  } 

4、创建一个新数组来存储修改后的数组内容,并且处理复制开始位置之前的元素复制要添加的新元素复制开始位置之后且未被删除的元素

const newArray = [];  

  // 
  for (let i = 0; i < start; i++) {  
      newArray.push(array[i]);  
  }  

  // 复制要添加的新元素  
  for (let item of itemsToAdd) {  
      newArray.push(item);  
  }  

  // 复制开始位置之后且未被删除的元素  
  for (let i = start + deleteCount; i < array.length; i++) {  
      newArray.push(array[i]);  
  }  

5、更新原数组,并返回被删除数组


  for (let i = 0; i < newArray.length; i++) {  
      array[i] = newArray[i];  
  }  
  array.length = newArray.length; // 确保原数组的长度正确  

  // 返回被删除的元素  
  return deletedElements;  

把这些代码片段组合到我们的customSplice函数中,就实现了array.splice

function customSplice(array, start, deleteCount, ...itemsToAdd) {  
  // 处理负数索引  
  if (start < 0) {  
      start = Math.max(0, array.length + start);  
  }  

  // 限制删除的元素数量不超过从start到数组末尾的元素数量  
  const maxDeleteCount = array.length - start;  
  deleteCount = (deleteCount > maxDeleteCount) ? maxDeleteCount : deleteCount;  

  // 创建一个新数组来存储被删除的元素  
  const deletedElements = [];  
  for (let i = 0; i < deleteCount; i++) {  
      deletedElements.push(array[start + i]);  
  }  

  // 创建一个新数组来存储修改后的数组内容  
  const newArray = [];  

  // 复制开始位置之前的元素  
  for (let i = 0; i < start; i++) {  
      newArray.push(array[i]);  
  }  

  // 复制要添加的新元素  
  for (let item of itemsToAdd) {  
      newArray.push(item);  
  }  

  // 复制开始位置之后且未被删除的元素  
  for (let i = start + deleteCount; i < array.length; i++) {  
      newArray.push(array[i]);  
  }  

  // 更新原数组  
  for (let i = 0; i < newArray.length; i++) {  
      array[i] = newArray[i];  
  }  
  array.length = newArray.length; // 确保原数组的长度正确  

  // 返回被删除的元素  
  return deletedElements;  
}  

使用示例

let myArray = [1, 2, 3, 4, 5];  
console.log(customSplice(myArray, 2, 2, 'a', 'b')); // 输出: [3, 4],myArray 变为 [1, 2, 'a', 'b', 5]
console.log(myArray)

函数逻辑简介:

  1. 处理了负数索引,将其转换为正数索引。
  2. 计算了要删除的元素数量,并确保它不会超过从 start 位置到数组末尾的元素数量。
  3. 创建了一个新数组 deletedElements 来存储被删除的元素。
  4. 创建了一个新数组 newArray 来存储修改后的数组内容。
  5. 通过循环将开始位置之前的元素、要添加的新元素以及开始位置之后且未被删除的元素复制到 newArray 中。
  6. 使用循环将 newArray 中的元素复制回原数组 array 中,并更新原数组的长度。
  7. 返回了被删除的元素数组 deletedElements