JS数组怎么按索引删除某个位置的元素

作者:纸飞机时间:2026-11-03 11:54:58浏览:173

详细讲解在 JavaScript 中如何按索引删除数组中某个位置的元素,涵盖 splice 原地删除操作与避坑要点、delete 关键字导致稀疏数组的常见误区、toSpliced 与 slice 的不可变删除方案,以及负索引与循环删除的边界处理。

JavaScript 开发技巧
在 JavaScript 中,按索引删除数组中某个指定位置的元素,最直接且标准的做法是调用数组的原生方法 array.splice(index, 1)。它会直接修改原数组,将指定索引处的元素移出,并将其后面的所有元素自动向前平移以填补空位。若业务场景要求保持原数据不变(例如在 React、Vue 3 或状态流转中),则可以使用 ES2023 推出的 array.toSpliced(index, 1),或者采用 slice() 搭配展开运算符,安全地返回一个排除了目标元素的新数组。
JS数组怎么按索引删除某个位置的元素
图 0:JavaScript 按索引删除数组元素的核心方法概览

一、标准原地删除:使用 splice() 方法

在无需保留原数组引用的普通开发场景中,Array.prototype.splice() 是 JavaScript 官方提供的标准原地修改方法。

1. 基本语法与调用方式

splice() 接收多个参数,在按索引删除单项元素时,核心关注前两个参数:

const removedItems = array.splice(startIndex, deleteCount);
  • startIndex(起始索引):从哪个位置开始操作(从 0 开始计数)。
  • deleteCount(删除数量):从起始索引开始连续删除多少个元素。若只需删除当前位置的一个元素,必须显式传入 1。
  • 返回值:包含被删除元素的新数组。如果不需要接收被删除的项,可直接忽略返回值。

2. 完整代码示例

// 示例 1:删除索引为 2 的元素(即第三个元素 'Cherry')
const fruits = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry'];

// 执行删除:从索引 2 开始,删除 1 个元素
const deleted = fruits.splice(2, 1);

console.log(fruits);  
// 示例输出:['Apple', 'Banana', 'Date', 'Elderberry']

console.log(deleted); 
// 示例输出:['Cherry'](被删除的元素存放在数组中返回)

console.log(fruits.length); 
// 示例输出:4(数组长度随之减少 1)
⚠️ 关键提醒:第二个参数切勿遗漏

如果调用时写成 fruits.splice(2) 而遗漏了 deleteCount,JavaScript 的默认行为是将索引 2 及其之后直到末尾的所有元素全部删除!因此,按索引删除单个元素时务必写全 splice(index, 1)。

JS数组怎么按索引删除某个位置的元素
图 1:splice(index, 1) 执行过程中的数组内存连续性与索引重排

二、常见误区:为什么不能使用 delete 关键字

不少刚接触 JavaScript 的开发者会联想到对象的属性删除语法 delete obj.prop,并尝试对数组执行 delete array[index]。这种做法在数组上通常是错误的。

1. delete 对数组的作用机理

在 JavaScript 中,数组本质上是特殊的对象,数字索引就是其属性名。使用 delete array[index] 只会将该索引属性从对象上移除,并把该位置置为“空槽(empty slot / hole)”,而不会调整数组的长度,也不会让后面的元素向前平移。

const numbers = [10, 20, 30, 40];

// 错误示范:使用 delete 关键字
delete numbers[1];

console.log(numbers);
// 示例输出:[10, empty, 30, 40]

console.log(numbers.length);
// 示例输出:4(长度并未减少!)

console.log(numbers[1]);
// 示例输出:undefined

2. 稀疏数组(Sparse Array)带来的隐患

执行 delete 后,原本紧凑密集的数组变成了稀疏数组。这会导致常规的高阶遍历方法出现反直觉的表现:

  • forEach()、map()、filter() 等迭代器在遍历时会自动跳过空槽,导致回调执行次数少于 length。
  • JSON.stringify() 序列化时,空槽会被强制转换为 null,造成数据格式被污染。
  • 现代 JavaScript 引擎(如 V8)会对密集数组进行底层布局优化,出现稀疏数组会使引擎退回到哈希字典模式,影响访问性能。
JS数组怎么按索引删除某个位置的元素
图 2:delete 导致的稀疏数组与 splice 维持紧凑数组的结构差异

三、不可变删除:返回全新数组的三种方案

在现代前端应用(如 React 状态管理、Redux、Vue 3 计算属性等)中,为了遵循不可变数据(Immutability)原则,开发者往往要求不修改原始数组,而是生成一个去除了目标索引项的新数组。以下是三种主流的不可变删除手段:

方案 1:toSpliced() 原生方法(现代标准,ES2023+)

ECMAScript 2023 正式引入了 Array.prototype.toSpliced()。它的参数形式与 splice() 完全一致,但区别在于它不会修改原数组,而是直接返回修改后的全新数组副本。

// 推荐方案(Node.js 20+、Chrome 110+、Safari 16+)
const list = ['Vue', 'React', 'Angular', 'Svelte'];

// 删除索引为 1 的项('React'),返回新数组
const updatedList = list.toSpliced(1, 1);

console.log(updatedList); 
// 示例输出:['Vue', 'Angular', 'Svelte']

console.log(list); 
// 示例输出:['Vue', 'React', 'Angular', 'Svelte'](原数组完好无损)

方案 2:slice() 与展开运算符合并(全环境通用)

如果运行环境需要兼容较早版本的浏览器或低版本 Node.js,可以使用 Array.prototype.slice()。通过分别截取目标索引前、后的两个片段,再使用展开运算符(...)拼接为一个新数组:

const original = ['A', 'B', 'C', 'D'];
const removeIndex = 2;

// 前半段:[0, 2) 即 ['A', 'B'];后半段:[3, 4) 即 ['D']
const result = [
  ...original.slice(0, removeIndex),
  ...original.slice(removeIndex + 1)
];

console.log(result);   // 示例输出:['A', 'B', 'D']
console.log(original); // 示例输出:['A', 'B', 'C', 'D']

这种方案在 ES6 及以上环境中完全原生支持,无需任何 Polyfill,执行性能非常优异。

方案 3:filter() 按索引排除(函数式过滤)

Array.prototype.filter() 的回调函数第二个参数会传入当前项的索引。只需判断索引是否不等于目标值即可:

const tags = ['HTML', 'CSS', 'JavaScript'];
const targetIndex = 0;

const filteredTags = tags.filter((_, index) => index !== targetIndex);

console.log(filteredTags); // 示例输出:['CSS', 'JavaScript']

filter() 书写简短,但需要注意:它会对数组中的每一个元素都执行一次判断,时间复杂度恒定为 O(N)。在对百万级超大数组进行单项删除时,其耗时会高于 slice 和 toSpliced。但在普通业务数组中,性能差异微乎其微。

JS数组怎么按索引删除某个位置的元素
图 3:不可变删除各方案处理数据流与原数组保护机制

四、边界场景与容易出错的细节

在实际工程中,索引值往往来自前端计算、路由参数或用户交互输入。处理以下边界条件可避免隐蔽的 Bug:

1. 支持负数索引的特性

splice() 和 toSpliced() 原生支持负数索引。当传入负数时,它表示从数组末尾倒数定位:

const items = ['first', 'second', 'third', 'last'];

// -1 表示倒数第一个元素
items.splice(-1, 1);
console.log(items); // 示例输出:['first', 'second', 'third']

// -2 表示倒数第二个元素
items.splice(-2, 1);
console.log(items); // 示例输出:['first', 'third']

2. 索引越界时的表现

  • 大于或等于数组长度:若 index >= arr.length,splice(index, 1) 不会报错,也不会删除任何元素,原数组保持不变。
  • 极小负数:若负数的绝对值大于数组长度(例如数组长 3,传入 -10),操作位置会被自动钳制在索引 0 处开始执行。

3. 在循环中按索引删除多个元素的“跳跃陷阱”

如果在循环中多次调用 splice() 删除元素,必须格外警惕:由于每次删除都会导致后续元素向前移动,正序递增的循环变量(i++)会漏掉紧随其后的下一个元素。

// ❌ 错误示范:正向循环删除
const nums = [1, 2, 2, 3];
for (let i = 0; i < nums.length; i++) {
  if (nums[i] === 2) {
    nums.splice(i, 1); // 删除后第二个 2 移到了当前 i 的位置,下一轮 i++ 会直接跳过它!
  }
}
console.log(nums); // 示例输出:[1, 2, 3](遗漏了一个 2)

// ✔ 正确做法 1:从后往前倒序循环(索引前移不影响未处理的前半部分)
for (let i = nums.length - 1; i >= 0; i--) {
  if (nums[i] === 2) {
    nums.splice(i, 1);
  }
}

// ✔ 正确做法 2:优先采用 filter() 批量排除,避免循环维护索引
const cleaned = nums.filter(n => n !== 2);

五、各删除方案特性对比与技术选型

为了方便在实际开发中快速选用恰当的方法,下表汇总了四种主要删除方式的对比:

方法名称 是否修改原数组 返回值 环境兼容性 典型推荐场景
splice(i, 1) 是(原地修改) 被删除项数组 所有 JS 环境 局部临时变量、算法题、内部缓存等追求极高执行效率与低内存开销的场景
toSpliced(i, 1) 否(纯函数) 排除目标项的新数组 ES2023+ (Node 20+) 现代 React/Vue 状态更新、前端工程化项目、追求代码语义规范的场景
slice + 展开 否(纯函数) 排除目标项的新数组 ES6+ (所有主流环境) 需要不可变特性、但项目需要兼顾老旧运行环境(如旧版 WebView 或低版本 Node)
filter((_, idx) => ...) 否(纯函数) 符合条件的新数组 ES5+ (所有主流环境) 根据多个条件复合过滤、或者根据元素内容与索引联合判断的场景
JS数组怎么按索引删除某个位置的元素
图 4:按索引删除数组元素的技术选型与最佳实践决策树
作者最新文章
相关文章
更多