如何通过值从数组中删除项目?

1368

有没有一种方法可以从 JavaScript 数组中移除一个元素?

给定一个数组:

var ary = ['three', 'seven', 'eleven'];

我想要做类似这样的事情:

removeItem('seven', ary);

我研究了splice(),但那只能按位置号删除,我需要一种可以按值删除项目的方法。


123
Array.filter() 翻译为 "数组过滤",它是 JavaScript 中的一个数组方法。该方法可用于创建一个新数组,其中包含原始数组中满足特定条件的所有元素。使用该方法需要提供一个回调函数,该函数接受三个参数:当前元素、元素索引和数组本身。回调函数应返回一个布尔值,指示当前元素是否应包含在新数组中。 - Eric Hodonsky
它也可以在这里找到:https://dev59.com/CG025IYBdhLWcg3w1ZoL#21408685这是基准测试:https://jsperf.com/array-without-benchmark-against-lodash - Ardi
我认为从数组中删除元素的最干净的方法是使用数组的ary.filter()方法。ary.filter(val => val !== 'seven')。这将返回一个新数组,其中包含除了“seven”之外的所有元素。 - Ali Raza
ary.splice(ary.indexOf(ID),1)只需使用这个简单的代码行就可以完成! - undefined
显示剩余3条评论
37个回答

2194
您可以像这样使用indexOf方法
var index = array.indexOf(item);
if (index !== -1) {
  array.splice(index, 1);
}

注意:您需要为IE8及以下版本添加shim

var array = [1,2,3,4]
var item = 3

var index = array.indexOf(item);
array.splice(index, 1);

console.log(array)


80
当索引不是“-1”时,对其进行循环。 - Colin Hebert
8
最好进行一次检查,仅在不等于“-1”时再执行拼接操作。有数百万个选项可供选择,请谨慎选择。http://jsperf.com/not-vs-gt-vs-ge/4 - ajax333221
35
如果您使用jQuery,可以使用$.inArray代替indexOf,它在各种浏览器上都兼容。 - Tamás Pap
4
请查看 https://dev59.com/CG025IYBdhLWcg3w1ZoL,该链接包含有关从数组中删除特定元素的信息。 - Dimuthu
43
请确保index!==(-1),即项目存在于数组中,否则您将删除数组中的最后一个元素。 - Ronen Rabinovici
显示剩余6条评论

762
一个简短的语句就可以完成它。
var arr = ['three', 'seven', 'eleven'];

// Remove item 'seven' from array
var filteredArray = arr.filter(function(e) { return e !== 'seven' })
//=> ["three", "eleven"]

// In ECMA6 (arrow function syntax):
var filteredArray = arr.filter(e => e !== 'seven')

这个使用了JS中的filter函数。它支持IE9及以上版本。

它的作用(来自文档链接):

filter()函数对数组中的每个元素调用一次提供的回调函数,并构造一个由所有导致回调返回一个强制转换为true值的值组成的新数组。回调仅为具有分配值的数组索引调用;它不为已删除或从未分配值的索引调用。没有通过回调测试的数组元素将被简单地跳过,并且不包含在新数组中。

因此,基本上,这与所有其他for (var key in ary) { ... }解决方案相同,只是for in结构从IE6开始受支持。

基本上,filter是一个更加美观(可以链式调用)方便的方法,与for in结构相比(据我所知)。


8
想知道为什么这个精简的一行代码没有得到更多的喜爱。+1 没有循环。使用 && 可以添加要删除的任意数量的值。 - user1299518
@bamboon filter函数检查元素是否符合条件。该函数逐个执行每个元素,并在返回“true”时,结果数组将保留该元素。如果返回“false”,则该元素被省略。 - Qwerty
@vlzvl 可能是因为我们中的一些人仍然需要支持IE8,这也排除了在Windows Script Host Version 5.8中使用它的可能性,例如,没有polyfill。 哎呀。 ;^) - ruffin
1
这非常简单,但要注意@SLaks提到的一个警告,它会创建数组的副本,并不影响变量的引用。 - tobylaroni
1
请注意,此解决方案会删除数组中所有值为“七”的元素,而不仅仅是像得到最高票的答案那样只删除第一个。 - Zach Saucier
这个解决方案也可以用于在对象数组中查找值,例如:routes = routes.filter(function (e) { return e.id !== id }); - quilkin

560

如果您无法添加到本地原型中,则此函数可以是全局函数或自定义对象的方法。它会从数组中删除与任何参数匹配的所有项。

Array.prototype.remove = function() {
    var what, a = arguments, L = a.length, ax;
    while (L && this.length) {
        what = a[--L];
        while ((ax = this.indexOf(what)) !== -1) {
            this.splice(ax, 1);
        }
    }
    return this;
};

var ary = ['three', 'seven', 'eleven'];

ary.remove('seven');

/*  returned value: (Array)
three,eleven
*/

使其成为全局变量-

function removeA(arr) {
    var what, a = arguments, L = a.length, ax;
    while (L > 1 && arr.length) {
        what = a[--L];
        while ((ax= arr.indexOf(what)) !== -1) {
            arr.splice(ax, 1);
        }
    }
    return arr;
}
var ary = ['three', 'seven', 'eleven'];
removeA(ary, 'seven');


/*  returned value: (Array)
three,eleven
*/

同时要考虑到IE8及以下版本的兼容性 -

if(!Array.prototype.indexOf) {
    Array.prototype.indexOf = function(what, i) {
        i = i || 0;
        var L = this.length;
        while (i < L) {
            if(this[i] === what) return i;
            ++i;
        }
        return -1;
    };
}

5
不,.prototype 属性是跨浏览器的。 - Casey Rodarmor
191
不要改变数组原型。这样会导致一些有趣的事情发生。 - szanata
30
@madeinstefano,可以举一两个有趣(差劲)的例子吗? - Majid Fouladpour
26
人们为什么会在数组原型中添加示例?堆栈溢出是为了学习良好的做法。 - Blair Anderson
10
@YonnTrimoreau 然后呢?定义一个不可枚举属性 Object.defineProperty(Array.prototype, "remove", {enumerable : false}); - naXa stands with Ukraine
显示剩余14条评论

150
你可以使用underscore.js。它确实让事情变得简单。
例如,使用以下内容:
var result = _.without(['three','seven','eleven'], 'seven');

并且 result 将会是 ['three','eleven']

在您的情况下,您需要编写的代码是:

ary = _.without(ary, 'seven')

它减少了您编写的代码。


18
我从未说过不要在其他地方使用库。如果代码看起来更清晰,那么我不介意包含一个库。为什么人们使用jQuery,而不是使用原始的JavaScript呢? - vatsal
11
因为库开发人员可以专注于使其库函数的功能快速、简洁且跨浏览器,而我可以专注于我的应用程序及其目的。这样可以节省我的思考时间,让我有更多时间来改进应用程序,而不必担心构成应用程序的小函数。有人已经发明了车轮,为什么每次造车时都要重新制造呢? - styks
12
嗨,Kelvin,我完全同意你的观点。有人发表了评论,但后来将其删除了。他说使用像Underscore这样的库不酷,我们不应该接受这样的回答。我试图回答它。 - vatsal
请注意,这不会直接修改数组;而是返回一个新的数组。 - gcscaglia
是的。如果要改变数组而不是返回一个新数组,请使用_.pull - undefined

83

你可以用以下两种方式来实现:

const arr = ['1', '2', '3', '4'] // we wanna delete number "3"
  1. 第一种方法:

arr.indexOf('3') !== -1 && arr.splice(arr.indexOf('3'), 1)
  • 第二种方法(ES6)特别是不会改变原始数据:

  • const newArr = arr.filter(e => e !== '3')
    

    60

    方法1

    var ary = ['three', 'seven', 'eleven'];
    var index = ary.indexOf('seven'); // get index if value found otherwise -1
    
    if (index > -1) { //if found
      ary.splice(index, 1);
    }
    

    方法2

    一行解决方案

    var ary = ['three', 'seven', 'eleven'];
    filteredArr = ary.filter(function(v) { return v !== 'seven' })
    
    
    // Or using ECMA6:
    filteredArr = ary.filter(v => v !== 'seven')
    

    3
    感谢您提供这段代码片段,它可能会提供一些有限的、即时的帮助。一个适当的解释将极大地改善其长期价值,因为它将展示出为什么这是一个好的问题解决方案,并使其对未来阅读者更有用,他们可能会有其他相似的问题。请编辑您的答案以添加一些解释,包括您所做的假设。 - Blue
    2
    在我的情况下,以下代码最为适用,因为我想从一个具有存储在变量中的值(要删除的值)的数组中进行删除。谢谢! - Akhil

    57

    看看这种方式:

    for(var i in array){
        if(array[i]=='seven'){
            array.splice(i,1);
            break;
        }
    }
    

    在一个函数中:

    function removeItem(array, item){
        for(var i in array){
            if(array[i]==item){
                array.splice(i,1);
                break;
            }
        }
    }
    
    removeItem(array, 'seven');
    

    20
    请记住,如果您修改此代码以避免“break”并继续循环以删除多个项目,则需要立即在splice之后重新计算i变量,例如:i--。这是因为您刚刚缩小了数组,否则您将跳过一个元素。 - Doug S
    4
    补充我之前的评论,代码将会是这样的:for (var i = 0; i < array.length; i++) {/等等.../ array.splice(i,1); i--; - Doug S
    嗨... 问题是,如何删除多个数组?我尝试了 removeItem(array, 'seven, eight') 但它没有起作用。 - HiDayurie Dave

    57
    最简单的解决方案是:

    array - 用于删除某些元素值的数组 valueForRemove; valueForRemove - 要删除的元素。

    array.filter(arrayItem => !array.includes(valueForRemove));
    

    更简单:

    array.filter(arrayItem => arrayItem !== valueForRemove);
    

    不太漂亮,但能正常工作:

    array.filter(arrayItem => array.indexOf(arrayItem) != array.indexOf(valueForRemove))
    

    不太好看,但能用:

    while(array.indexOf(valueForRemove) !== -1) {
      array.splice(array.indexOf(valueForRemove), 1)
    }
    

    P.S. filter() 方法根据所提供的函数实现的测试,创建一个新数组并筛选所有通过测试的元素。请参见https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter


    这甚至离正确答案还很远吗?你应该编辑一下以提供可工作的示例。现在很令人困惑。 - Arnas Pecelis
    2
    虽然我喜欢这种方法,因为它使用不可变的数据结构,但这并不是一个万能的解决方案,因为有时开发人员确实希望在原地改变数组。 - feihcsim
    filter() 方法通过提供的函数实现测试来创建一个新数组,并返回所有通过测试的元素。参见 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/filter - Jackkobec
    1
    这个作为赋值语句的右侧是有效的:newArray = array.filter... 然后:array = newArray,该项就从 array 中消失了。 - Preston
    关于 filter() 的文档绝对易懂。 - Jackkobec

    46

    您可以创建自己的方法,通过传递数组和要删除的值:

    function removeItem(arr, item){
     return arr.filter(f => f !== item)
    }
    

    然后您可以这样调用:

    ary = removeItem(ary, 'seven');
    

    37

    这里有一个使用jQuery的inArray函数的版本:

    var index = $.inArray(item, array);
    if (index != -1) {
        array.splice(index, 1);
    }
    

    20
    Splice 支持负数索引以从末尾获取元素,因此如果未找到该项,则该代码将从数组中删除最后一个元素。 - dmeglio
    2
    @dman2306 哦,直到现在才看到你的评论,但那是一个非常好的观点。已经为该问题进行了修复。 - CorayThan

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接