在JavaScript开发中,删除数组里的某个元素几乎是绕不开的操作。但这个看似简单的需求,实际写起来却有不少讲究:是按索引删还是按值删?删除一个还是所有匹配项?能不能改变原数组?不同的选择对应完全不同的方法。如果随手使用delete操作符,还可能给数组留下难以察觉的空洞。本文将系统介绍几种常用且可靠的删除方式,并分析各自的适用场景。

splice:按索引删除的首选方案
splice是删除数组元素最经典的方法,它会直接修改原数组,并返回被删除的元素组成的新数组。它的完整签名是array.splice(start, deleteCount, item1, item2, ...),其中start表示起始索引,deleteCount表示要删除的元素个数,后面的参数可选,用于在删除位置插入新元素。
如果只想删除索引为2的一个元素,可以这样写:
let arr = ['a', 'b', 'c', 'd', 'e']; let removed = arr.splice(2, 1); // 从索引2开始删除1个 console.log(arr); // ['a', 'b', 'd', 'e'] console.log(removed); // ['c'],返回被删除的元素
如果省略deleteCount参数,splice会从起始位置一直删到数组末尾。另外start还支持负数,比如-1代表最后一个元素,这在删除尾部元素时很方便。需要注意的是,splice是原地操作,如果其他变量引用了同一个数组,它们也会感知到这次修改,这在某些场景下可能引发意外问题。
按值删除:indexOf与splice配合使用
实际业务中往往不知道元素的索引,只知道要删除的值,这时可以先通过indexOf找到索引,再用splice删除:
let arr = ['苹果', '香蕉', '橘子', '葡萄'];
let index = arr.indexOf('橘子');
if (index !== -1) {
arr.splice(index, 1);
}
console.log(arr); // ['苹果', '香蕉', '葡萄']这里有个细节必须注意:indexOf在找不到元素时返回-1,如果不做判断直接执行splice(-1, 1),负索引会被解释为从末尾数起,结果误删了最后一个元素。这是一个非常常见的坑,写代码时务必加上index !== -1的判断。
如果数组中存在多个相同的值,上面的写法只会删除第一个匹配项。要删除所有匹配元素,可以用循环反向遍历:
let arr = [1, 2, 3, 2, 4, 2];
for (let i = arr.length - 1; i >= 0; i--) {
if (arr[i] === 2) {
arr.splice(i, 1);
}
}
console.log(arr); // [1, 3, 4]之所以要反向遍历,是因为正向遍历时删除元素会导致后面的元素前移,索引随之变化,容易漏删。反向遍历则不受影响,因为已检查过的索引不会因为前面的删除而改变。
filter:不改原数组的函数式方案
如果不想修改原数组,而是希望得到一个过滤后的新数组,filter是最佳选择。它的语义是保留所有满足条件的元素,换个角度理解就是删除所有不满足条件的元素:
let arr = [1, 2, 3, 2, 4, 2]; let newArr = arr.filter(item => item !== 2); console.log(newArr); // [1, 3, 4] console.log(arr); // [1, 2, 3, 2, 4, 2],原数组不变
filter的优势在于写法简洁、天然支持删除所有匹配项,而且不会产生副作用,特别适合React这类强调不可变数据流的框架中。配合箭头函数,一行代码就能表达清楚意图。它的缺点是会创建新数组,如果数组非常大且删除操作频繁,会带来一定的内存和性能开销。
对于对象数组,filter同样适用。比如删除所有id为特定值的用户:
let users = [
{ id: 1, name: '张三' },
{ id: 2, name: '李四' },
{ id: 3, name: '王五' }
];
let result = users.filter(user => user.id !== 2);
console.log(result); // [{id:1,...}, {id:3,...}]findIndex:处理对象数组的利器
对于对象数组按条件删除单个元素,findIndex比indexOf更灵活,因为indexOf对对象只能做引用比较,而findIndex可以传入自定义判断函数:
let users = [
{ id: 1, name: '张三' },
{ id: 2, name: '李四' }
];
let index = users.findIndex(user => user.id === 2);
if (index !== -1) {
users.splice(index, 1);
}
console.log(users); // [{id:1, name:'张三'}]这种写法先通过条件定位索引再删除,既保留了对原数组的直接操作,又能用任意复杂度的条件判断,是管理列表数据时的常见组合拳。同样要记得处理-1的情况,避免负索引带来的误删。
为什么不要用delete操作符
很多初学者会想当然地使用delete arr[1]来删除元素,这种写法语法上没问题,但结果往往不符合预期:
let arr = ['a', 'b', 'c']; delete arr[1]; console.log(arr); // ['a', empty, 'c'] console.log(arr.length); // 3,长度没变 console.log(arr[1]); // undefined,留下空洞
delete只是把该位置的值变成了empty,数组的length不变,遍历时这个空洞表现为undefined,JSON序列化时它又会消失,这种不一致的行为很容易埋下隐患。因此删除数组元素应该始终使用splice或filter,delete只适合删除对象的属性。
方法对比与选型建议
下面通过一个表格对比这几种方式的核心差异:
| 方法 | 是否改变原数组 | 删除依据 | 能否删多个 |
|---|---|---|---|
| splice | 是 | 索引 | 可以,指定数量 |
| indexOf + splice | 是 | 值 | 需配合循环 |
| findIndex + splice | 是 | 自定义条件 | 需配合循环 |
| filter | 否 | 自定义条件 | 天然支持 |
| delete | 是(但留空洞) | 索引 | 不推荐 |
简单总结选型思路:知道索引就用splice直接删;知道值就indexOf加splice;删所有匹配项或不想动原数组就用filter;对象数组按条件定位用findIndex。日常开发中还可以把这些逻辑封装成工具函数,例如:
// 通用删除函数:删除数组中所有满足条件的元素,返回新数组
function removeItem(arr, predicate) {
return arr.filter(typeof predicate === 'function' ? predicate : item => item !== predicate);
}
let nums = [1, 2, 3, 2, 5];
console.log(removeItem(nums, 2)); // [1, 3, 5]
console.log(removeItem(nums, n => n > 2)); // [1, 2, 2]掌握这些方法的本质区别后,面对不同的删除需求就能快速做出正确选择,写出既简洁又健壮的代码。
javascript数组删除元素splicefilter修改时间:2026-09-15 06:23:20