利用JS获取的数组下标删除或替换指定元素

作者:青柠

时间:2026-11-03

浏览:526

详细讲解在JavaScript中利用获取的数组下标删除或替换指定元素的方法。包含splice原地修改、ES2023不可变更新toSpliced与with、防范-1误删末尾元素与倒序循环删除等实用技巧。

文章目录
在 JavaScript 开发中,根据检索获取到的数组下标(Index)对目标位置进行删除或替换,最经典且高效的做法是使用内置的 Array.prototype.splice() 方法;而在注重无副作用的现代前端场景中,可直接选用 ES2023 引入的不可变方法 toSpliced() 与 with()。无论采用哪种方式,完整操作路径均由“定位下标”、“有效性防御检查”与“执行更新”三步构成。
利用JS获取的数组下标删除或替换指定元素
图 1:JavaScript 数组下标操作的核心路径概览(缩略图)

一、获取目标下标与有效性防御检查

在对数组进行更新前,首先需要获取目标元素在数组中的下标位置。根据元素是简单基本数据类型还是复杂引用对象,JavaScript 提供了对应的检索 API。

1. 检索下标的基础方式

对于字符串、数字等基础类型数组,推荐使用 indexOf() 或 lastIndexOf();对于对象数组或需要自定义比对条件的场景,则应使用 findIndex() 或 findLastIndex()。

// 示例 1:简单类型使用 indexOf() 获取下标
const fruits = ['苹果', '香蕉', '橙子', '葡萄'];
const targetIndex = fruits.indexOf('橙子'); // 返回 2

// 示例 2:对象数组使用 findIndex() 获取下标
const userList = [
  { id: 101, name: '张三' },
  { id: 102, name: '李四' },
  { id: 103, name: '王五' }
];
const userIndex = userList.findIndex(item => item.id === 102); // 返回 1

2. 为什么必须检查 index !== -1

当 indexOf 或 findIndex 未匹配到符合条件的元素时,统一会返回数值 -1。如果不加判断直接调用 splice,就会引发非常严重的逻辑漏洞:

⚠️ 关键陷阱:splice() 接收负数下标时,会将负数视为倒数索引(例如 -1 即代表末尾最后一个元素)。若未找到目标元素时直接执行 arr.splice(-1, 1),程序不仅不会报错,反而会将数组最后一个元素误删!因此,执行任何下标操作前,必须进行安全校验。
利用JS获取的数组下标删除或替换指定元素
图 2:从检索下标到安全执行的判定与分支流程

二、原地修改:直接删除或替换原数组元素

在不需要保留原数组引用的普通业务场景中,原地修改(Mutable)执行速度最快,内存消耗最少。

1. 利用下标删除元素:splice(index, count)

Array.prototype.splice(startIndex, deleteCount) 能够从指定的起始下标开始,连续删除指定数量的元素,并以新数组的形式返回被删除的项。

const list = ['A', 'B', 'C', 'D'];
const index = list.indexOf('B');

if (index !== -1) {
  const deletedItems = list.splice(index, 1);
  console.log('删除后的原数组:', list);         // 输出示例:['A', 'C', 'D']
  console.log('被移除的元素项:', deletedItems); // 输出示例:['B']
}

2. 利用下标替换元素:直接赋值与 splice 传参

替换指定下标位置的元素有两种常用做法:

  • 直接索引赋值(推荐单项替换):语法为 arr[index] = newValue。这是最纯粹、性能最高的单元素覆盖方式。
  • 使用 splice 替代插入:语法为 arr.splice(index, 1, newValue)。它在移除旧元素的同时,在原位置压入新元素,适合需要同时获取被替换项的场景。
const tasks = ['未开始', '进行中', '已挂起'];
const target = tasks.indexOf('已挂起');

if (target !== -1) {
  // 做法一:直接通过索引重新赋值
  tasks[target] = '已完成';
  console.log(tasks); // 输出示例:['未开始', '进行中', '已完成']

  // 做法二:利用 splice 原地替换并获取旧值
  const [oldVal] = tasks.splice(target, 1, '已归档');
  console.log(tasks);  // 输出示例:['未开始', '进行中', '已归档']
  console.log(oldVal); // 输出示例:'已完成'
}
利用JS获取的数组下标删除或替换指定元素
图 3:splice() 原地删除与替换操作时的数组内存与索引变化原理

三、不可变更新:不破坏原数组的现代解法

在 React、Vue、Pinia 或 Redux 等现代状态管理中,推荐遵循“状态不可变(Immutability)”原则。修改数据时不应直接改变原始数组,而应返回一份全新的数组引用,以便框架准确检测到引用变更触发视图渲染。

1. ES2023 原生不可变方法:toSpliced 与 with

现代 ECMAScript(ES2023 / Node.js 20+ / 各大现代浏览器)为数组原型提供了原生的不可变版本:

  • Array.prototype.toSpliced(start, deleteCount, ...items):功能同 splice,但不修改原数组,直接返回修改后的新数组。
  • Array.prototype.with(index, value):传入目标下标与新值,返回一个对应索引被替换后的新数组。
const original = ['Vue', 'React', 'Angular'];
const targetIndex = original.indexOf('Angular');

if (targetIndex !== -1) {
  // 不可变删除
  const afterDelete = original.toSpliced(targetIndex, 1);
  console.log(afterDelete); // 输出示例:['Vue', 'React']
  console.log(original);    // 输出示例:['Vue', 'React', 'Angular'](原数组未受影响)

  // 不可变替换
  const afterReplace = original.with(targetIndex, 'Svelte');
  console.log(afterReplace); // 输出示例:['Vue', 'React', 'Svelte']
  console.log(original);     // 输出示例:['Vue', 'React', 'Angular']
}

2. 传统环境中的不可变兼容写法

在需要支持旧版运行时或打包目标环境较低时,可以通过 slice() 结合扩展运算符 ... 达到完全相同的效果:

// 兼容模式:不可变删除
const removeIndex = 1;
const nextList1 = [
  ...original.slice(0, removeIndex),
  ...original.slice(removeIndex + 1)
];

// 兼容模式:不可变替换
const nextList2 = [
  ...original.slice(0, removeIndex),
  '新元素',
  ...original.slice(removeIndex + 1)
];
利用JS获取的数组下标删除或替换指定元素
图 4:原地修改模式与不可变更新模式的特性对比

四、高频实战场景与常见问题排查

1. 循环遍历中按下标删除:“索引塌陷”陷阱

当需要在一个数组中循环删除多个满足条件的元素时,初学者常犯的错误是在正序 for 循环中直接使用 splice:

// ❌ 错误示范:正序循环删除会导致漏判
const numbers = [1, 2, 2, 3, 4];
for (let i = 0; i < numbers.length; i++) {
  if (numbers[i] === 2) {
    numbers.splice(i, 1); // 删除后后面的元素向前平移,但 i 依然自增,导致下一个 2 被跳过!
  }
}
// 实际输出示例:[1, 2, 3, 4](第二个 2 没有被删掉!)

正确解法:倒序遍历。从数组末尾向前遍历(let i = arr.length - 1; i >= 0; i--),删除后面的元素不会对前面尚未遍历到的元素下标造成任何影响。

// 正确示范:倒序循环删除
const validNumbers = [1, 2, 2, 3, 4];
for (let i = validNumbers.length - 1; i >= 0; i--) {
  if (validNumbers[i] === 2) {
    validNumbers.splice(i, 1);
  }
}
console.log(validNumbers); // 输出示例:[1, 3, 4](完全正确)

2. 常见问题排查与速查对照

疑难现象 / 疑问 根本原因 解决办法
本意删除指定项,却把数组最后一项删除了 检索返回了 -1,直接传入 splice(-1, 1) 触发倒数删除 增加前置判断:if (index >= 0 && index < arr.length)
使用 delete arr[index] 元素变为了 empty delete 运算符仅清空值并保留空槽位(变成稀疏数组),不改变长度 必须使用 arr.splice(index, 1) 才能彻底移除并收拢下标
修改了数组后 React 页面没有重新渲染 直接调用 splice 修改了同一引用,Diff 比较判定数据未变 改用 setList(list.toSpliced(i, 1)) 或 [...list.slice(...)]
利用JS获取的数组下标删除或替换指定元素
图 5:JavaScript 数组下标删除与替换的技术选型与核心铁律

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章