题 如何从JavaScript中删除数组中的特定元素?


我有一个整数数组,我正在使用 .push() 向其添加元素的方法。

有没有一种简单的方法从数组中删除特定元素?相当于像 array.remove(int);

我必须使用 核心 JavaScript - 没有 框架是允许的。


6131
2018-04-23 22:17


起源


如果你需要支持 <IE9 (叹)然后检查 这个问题 关于 indexOf 在IE中。 - Scotty.NET
(lodash)array = ['a','b','c']; _.pull(array,'a')// array => ['b','c'];也可以看看 stackoverflow.com/questions/5767325/... - Chun Yang
过滤方法 可以做你想做的。 - Salvador Dali
你可以使用删除,但它不会重新排列索引,而是将此槽设置为'undefined×1'。例如:var list = [1,2,3,4,5,6] - > delete list [1] - > [1,undefined×1,3,4,5,6]。 - DevWL
这里是两个主要可能性的性能基准: jsben.ch/#/b4Ume - EscapeNetscape


答案:


找出 index 要删除的数组元素,然后删除该索引 splice

splice()方法通过删除来更改数组的内容   现有元素和/或添加新元素。

var array = [2, 5, 9];
var index = array.indexOf(5);
if (index > -1) {
  array.splice(index, 1);
}
// array = [2, 9]

第二个参数 splice 是要删除的元素数。注意 splice 修改数组并返回一个包含已删除元素的新数组。


注意浏览器支持indexOf 是有限的


8923
2018-04-23 22:23



@Peter,是的,你可能是对的。本文解释了更多,并为不兼容的浏览器提供了一种解决方法: developer.mozilla.org/en/JavaScript/Reference/Global_Objects/... - Tom Wadley
危险!如果您正在使用动态值(在数组中添加和删除动态值)并且数组中不存在值(索引变为-1),则上面的代码将删除数组的最后一个元素。 - Adrian P.
@AlexandreWiechersVaz当然它保留了秩序,如果没有,那么它绝对毫无价值 - TheZ
您可以通过包含代码来克服IE浏览器支持问题 在这里给出
@AdrianP。 array.indexOf(testValue) 在空数组上将为-1,如果你正在测试,那么没有拼接。也许答案已经改变了。 - UpTheCreek


我不知道你的期望 array.remove(int) 表现。我可以想到你可能想要的三种可能性。

在索引处删除数组的元素 i

array.splice(i, 1);

如果要删除每个具有值的元素 number 从数组:

for(var i = array.length - 1; i >= 0; i--) {
    if(array[i] === number) {
       array.splice(i, 1);
    }
}

如果你只想在索引处创建元素 i 不再存在,但您不希望其他元素的索引发生更改:

delete array[i];

896
2018-04-23 22:20



delete 不是从数组中删除元素的正确方法! - Felix Kling
@FelixKling这取决于它是否有效,如果你想这样做 array.hasOwnProperty(i) 回报 false 并让该位置的元素返回 undefined。但我承认,这不是一件非常普通的事情。 - Peter Olson
delete 不会更新数组的长度也不会真正擦除元素,只会用特殊值替换它 undefined。 - diosney
@diosney当你说它没有真正抹去元素时,我不知道你的意思。此外,它不仅仅是简单地用该索引替换该索引处的值 undefined:它从数组中删除索引和值,即之后 delete array[0], "0" in array 将返回false。 - Peter Olson
如果要处理命名属性,delete是一种很好的机制 var array=[];array['red']=1;array['green']=2;array['blue']=3;delete array['green']; - Jefferey Cave


编辑于2016年10月

在这个代码示例中我使用 “array.filter(......)” 函数从数组中删除不需要的项目,此函数不会更改原始数组并创建一个新数组。如果您的浏览器不支持此功能(例如版本9之前的IE或版本1.5之前的Firefox),请考虑使用 来自Mozilla的过滤器polyfill

删除项目(ECMA-262 Edition 5 code aka oldstyle JS)

var value = 3

var arr = [1, 2, 3, 4, 5, 3]

arr = arr.filter(function(item) { 
    return item !== value
})

console.log(arr)
// [ 1, 2, 4, 5 ]

删除项目(ES2015代码)

let value = 3

let arr = [1, 2, 3, 4, 5, 3]

arr = arr.filter(item => item !== value)

console.log(arr)
// [ 1, 2, 4, 5 ]

重要 ES2015“()=> {}”IE中根本不支持箭头功能语法,Chrome版本为45版本,Firefox版本为22版本,Safari版本为10版本。要在旧浏览器中使用ES2015语法,您可以使用 BabelJS


删除多个项目(ES2016代码)

此方法的另一个优点是您可以删除多个项目

let forDeletion = [2, 3, 5]

let arr = [1, 2, 3, 4, 5, 3]

arr = arr.filter(item => !forDeletion.includes(item))
// !!! Read below about array.includes(...) support !!!

console.log(arr)
// [ 1, 4 ]

重要 IE中根本不支持“array.includes(...)”功能,47版本之前的Chrome版本,43版本之前的Firefox版本,9版本之前的Safari版本以及14版本之前的Edge版本 这是来自Mozilla的polyfill

删除多个项目(尖端实验性JavaScript ES2018?)

// array-lib.js

export function remove(...forDeletion) {
    return this.filter(item => !forDeletion.includes(item))
}

// main.js

import { remove } from './array-lib.js'

let arr = [1, 2, 3, 4, 5, 3]

// :: This-Binding Syntax Proposal
// using "remove" function as "virtual method"
// without extending Array.prototype
arr = arr::remove(2, 3, 5)

console.log(arr)
// [ 1, 4 ]

在BabelJS中自己尝试:)

参考


678
2017-12-19 19:54



但是,有时我们想要从原始数组中删除元素(非永久),例如Angular 2 * ngFor指令中使用的数组 - Ravinder Payal
比公认的解决方案更好,因为它不假设只出现一次匹配,并且不可变性更可取 - Greg
使用过滤器比使用接头好得多。太简单。 - user3344977
filter 对于一个大阵列来说必须慢得多吗? - Nathan
超慢的方法。 - highmaintenance


取决于你是否想留空。

如果你想要一个空插槽,删除就可以了:

delete array[ index ];

如果你不这样做,你应该使用 拼接 方法:

array.splice( index, 1 );

如果你需要该项的值,你可以只存储返回的数组的元素:

var value = array.splice( index, 1 )[0];

如果您想按某种顺序进行,可以使用 array.pop() 对于最后一个或 array.shift() 对于第一个(并且都返回项目的值)。

如果你不知道项目的索引,你可以使用 array.indexOf( item ) 得到它(在一个 if() 获得一个项目或一个 while() 得到所有这些)。 array.indexOf( item ) 如果未找到,则返回索引或-1。


359
2018-04-23 22:32



值得注意的是 var value 不会存储已删除的值,而是包含已删除值的数组。 - Jakub
delete 不是从数组中删除元素的正确方法! - Progo
如果要“清空插槽”,请使用 array[index] = undefined;。运用 delete 会破坏优化。 - Bergi
@Jakub非常好的评论,因为了解我失去了很多时间,并认为我的应用程序代码以某种方式被打破... - Pascal


一位朋友遇到了问题 Internet Explorer 8中,并告诉我他做了什么。我告诉他这是错的,他告诉我他在这里得到了答案。当前的最佳答案不适用于所有浏览器(例如Internet Explorer 8),它只会删除第一次出现的项目。

从数组中删除所有实例

function remove(arr, item) {
    for (var i = arr.length; i--;) {
        if (arr[i] === item) {
            arr.splice(i, 1);
        }
    }
}

它向后循环遍历数组(因为索引和长度将随着项目的移除而改变)并删除项目(如果已找到)。它适用于所有浏览器。


228
2017-08-10 19:21



@sroes它不应该是因为循环开始于 i = arr.length -1 要么 i-- 使其与最大索引相同。 arr.length 只是一个初始值 i。 i-- 一直会 truthy (并在每个循环op减少1)直到它等于 0 (一个假值)然后循环将停止。 - gabeno
第二个功能效率很低。在每次迭代时,“indexOf”将从数组的开头开始搜索。 - Ujeenator
@AmberdeBlack,关于超过1次出现的集合 项目,打电话给 过滤方法而不是 arr.filter(function (el) { return el !== item }),避免多次改变阵列的需要。这会消耗更多的内存,但运行效率更高,因为需要完成的工作量更少。 - Eugene Kuzmenko
@AlJey,它只能从IE9 +获得。它仍有可能无效。 - Ujeenator
这个答案对我有用,因为我需要删除几个项目但不按任何特定顺序删除。 for循环的向后进展在此处理完美地从阵列中移除项目。 - mintedsky


有两种主要方法:

  1. 拼接()anArray.splice(index, 1);

  2. 删除delete anArray[index];

对数组使用delete时要小心。删除对象的属性很好,但对数组不太好。最好使用 splice 对于数组。

请记住,当你使用时 delete 对于数组,你可能会得到错误的结果 anArray.length。换一种说法, delete 会删除元素但不会更新length属性的值。

使用删除后,您还可能会在索引号中出现漏洞,例如:你可能最终得到索引1,3,4,8,9,11和使用删除之前的长度。 在那种情况下,所有索引 for 循环会崩溃,因为索引不再是顺序的。

如果你被迫使用 delete 出于某种原因,那么你应该使用 for each 需要循环遍历数组时循环。事实上,如果可能的话,总是避免使用索引for循环。这样,代码将更加健壮,并且不易出现索引问题。


131
2017-12-21 11:32





Array.prototype.remByVal = function(val) {
    for (var i = 0; i < this.length; i++) {
        if (this[i] === val) {
            this.splice(i, 1);
            i--;
        }
    }
    return this;
}
//Call like
[1, 2, 3, 4].remByVal(3);

Array.prototype.remByVal = function(val) {
    for (var i = 0; i < this.length; i++) {
        if (this[i] === val) {
            this.splice(i, 1);
            i--;
        }
    }
    return this;
}

var rooms = ['hello', 'something']

rooms = rooms.remByVal('hello')

console.log(rooms)


104
2018-04-23 22:20



我不是这种方法的忠实粉丝。如果您最终使用不同的库或框架,它们最终可能会相互冲突。 - Charlie Kilian
这也很好用,我最终选择了indexOf函数。谢谢您的帮助! - Walker
不好主意,看这篇文章: stackoverflow.com/questions/948358/array-prototype-problem - MMeah
如果你正在做的话 for in 在阵列上,你已经有问题了。 - Zirak
如果你这样做 for in 在数组上,你已经有了更大的问题。 - Rainb


没有必要使用 indexOf 要么 splice。但是,如果您只想删除一个元素,它会表现得更好。

查找并移动(移动):

function move(arr, val) {
  var j = 0;
  for (var i = 0, l = arr.length; i < l; i++) {
    if (arr[i] !== val) {
      arr[j++] = arr[i];
    }
  }
  arr.length = j;
}

使用 indexOf 和 splice (指数):

function indexof(arr, val) {
  var i;
  while ((i = arr.indexOf(val)) != -1) {
    arr.splice(i, 1);
  }
}

仅限使用 splice (拼接):

function splice(arr, val) {
  for (var i = arr.length; i--;) {
    if (arr[i] === val) {
      arr.splice(i, 1);
    }
  }
}

nodejs上运行时间为1000个元素(平均超过10000次运行)的数组:

指数 大约慢10倍 移动。即使通过删除呼叫改进 indexOf 在 拼接 它表现得比 移动

Remove all occurrences:
    move 0.0048 ms
    indexof 0.0463 ms
    splice 0.0359 ms

Remove first occurrence:
    move_one 0.0041 ms
    indexof_one 0.0021 ms

82
2017-09-19 01:53



看起来这里提出的'move'方法应该适用于所有浏览器,并且还避免创建额外的数组;这里的大多数其他解决方案都存在一个或两个问题。我认为这个应该得到更多的选票,即使它看起来不那么“漂亮”。 - sockmonk