如何从JavaScript的数组中删除一个元素

2020-02-08大约8分钟

JavaScript提供了许多从一个数组(Array)中删除一个元素。有许多第三方提供的库可以轻松完成这个事情,比如Lodash等,不过我们今天主要说用最朴素的JavaScript看看如何实现。

如果你知道要删除元素的位置

假定你有一个数组,并且要删除元素的位置是i

一个方法是用slice()

const items = ['a', 'b', 'c', 'd', 'e', 'f'];
const i = 2;
const filteredItems = items.slice(0, i).concat(items.slice(i + 1, items.length));
console.log(filteredItems);
// ["a","b","d","e","f"]

数组的方法slice()接收两个参数,第一个参数是元素的位置,第二个参数是元素的数量,从这个数组里建一个新的数组,并把从指定位置开始的取出指定数量的元素放到新数组。上面的例子里,我们把要删除的元素前面的部分放到一个新数组,后面的部分也放到一个新数组,然后把两个数组用concat()再合并起来得到最终结果。

如果你知道要删除的值

这种情况下,用数组的filter()就比较好,这是一种更具声明式的方法:

const items = ['a', 'b', 'c', 'd', 'e', 'f'];
const valueToRemove = 'c';
const filteredItems = items.filter(item => item !== valueToRemove);
console.log(filteredItems);
// ["a","b","d","e","f"]

上面是ES6版本的代码,用了箭头函数。如果你用的是较老的浏览器,上面的例子跑不起来,可以用ES6版本的代码:

var items = ['a', 'b', 'c', 'd', 'e', 'f'];
var valueToRemove = 'c';
var filteredItems = items.filter(function(item) {
  return item !== valueToRemove;
});
console.log(filteredItems);
// ["a","b","d","e","f"]

或者你可以用Babel把ES6代码转成ES5的代码来支持旧的浏览器,好处是你可以使用更现代的JavaScript语言。

删除多个元素

如果你不是删除数组里一个元素,而是多个元素呢?

通过位置(index)

你可以通过创建一个函数,然后依次删除元素:

const items = ['a', 'b', 'c', 'd', 'e', 'f'];

const removeItem = (items, i) =>
  items.slice(0, i-1).concat(items.slice(i, items.length));

let filteredItems = removeItem(items, 3);
filteredItems = removeItem(filteredItems, 5);
console.log(filteredItems);
//["a", "b", "d", "e"]

通过值

你可以在filter函数里直接判断是否要过滤:

const items = ['a', 'b', 'c', 'd', 'e', 'f'];
const valuesToRemove = ['c', 'd'];
const filteredItems = items.filter(item => !valuesToRemove.includes(item));
console.log(filteredItems);
// ["a", "b", "e", "f"]
避免操作原始的数组splice()这个方法(不是slice())是在原始数组上做操作,要尽量避免。

关于性能考虑

上面两种做法,分别根据元素的位置和值去删除。根据位置删除是用slice()函数,这种方法要创建3个新数组,而数组的filter()方法只会创建一个新数组,所以理应效率要高一些。

下面的测试代码,测试循环10000次的性能比较:

const items = ['a', 'b', 'c', 'd', 'e', 'f'];

const removeItem = (items, i) =>
  items.slice(0, i-1).concat(items.slice(i, items.length));

console.time('ByIndex');
for (let i = 0; i < 10000; i++)
{
	let filteredItems = removeItem(items, 3);
	filteredItems = removeItem(filteredItems, 5);
}
console.timeEnd('ByIndex');

const valuesToRemove = ['c', 'd'];
console.time('ByValue');
for (let i = 0; i < 10000; i++)
{
	const filteredItems = items.filter(item => !valuesToRemove.includes(item));
}
console.timeEnd('ByValue');

在Chrome上大致是这样的结果:

方法 时间
ByIndex 14.24ms
ByValue 9.46ms

两者差异不大,所以从性能角度来看,至少在Chrome浏览器上,两种方法都是可以用的。

(由于IE不支持console.time(),所以上面的测试代码无法在IE上执行)