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

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

有没有一种简单的方法可以从数组中删除特定元素?等价于array.remove(number);

我必须使用核心 JavaScript - 不允许使用框架。

答案

使用indexOf查找要删除的数组元素的index ,然后使用splice删除该索引。

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

const array = [2, 5, 9];

console.log(array);

const index = array.indexOf(5);
if (index > -1) {
  array.splice(index, 1);
}

// array = [2, 9]
console.log(array);

splice的第二个参数是要删除的元素数。请注意, splice会在适当位置修改数组,并返回一个包含已删除元素的新数组。

我不知道您期望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];

于 2016 年 10 月编辑

  • 做到简单,直观和明确( Occam 的剃刀
  • 做到不可变(原始数组保持不变)
  • 如果您的浏览器不支持标准 JavaScript 函数,请执行此操作 - 使用 polyfill

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

删除项目(ECMA-262 版本 5 代码又称为旧式 JavaScript)

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 ]

删除项目(ECMAScript 6 代码)

let value = 3

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

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

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

重要说明 ECMAScript 6 的箭头函数语法完全不支持 Internet Explorer,45 之前的 Chrome,22 之前的 Firefox 和 10 之前的 Safari。要在旧的浏览器中使用 ECMAScript 6 语法,可以使用BabelJS


删除多个项目(ECMAScript 7 代码)

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

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 ]

重要提示 “array.includes(...)” 功能在 Internet Explorer,47 之前的 Chrome,43 之前的 Firefox,9 之前的 Safari 和 14 之前的 Edge 中完全不支持,因此这里是 Mozilla 的 polyfill

删除多个项目(将来可能)

如果“此绑定语法”提议曾经被接受,则可以执行以下操作:

// 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 中自己尝试:)

参考

这取决于您是否要保留空白点。

如果您确实想要一个空插槽,则可以删除:

delete array[index];

如果不这样做,则应使用splice方法:

array.splice(index, 1);

而且,如果您需要该项目的值,则可以只存储返回的数组的元素:

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

如果您想按某种顺序进行操作,则可以将array.pop()用于最后一个,或者将array.shift()用于第一个(并且两者也都返回该项的值)。

而且,如果您不知道该项目的索引,则可以使用array.indexOf(item)来获取它(在if()中获取一个项目, while()while()中获取所有它们)。 array.indexOf(item)返回索引,如果未找到则返回 - 1。

一个朋友在Internet Explorer 8 中遇到问题,向我展示了他的工作。我告诉他这是错误的,他告诉我他在这里得到了答案。当前的最佳答案不能在所有浏览器(例如 Internet Explorer 8)中都起作用,并且只会删除该项目的第一个匹配项。

从阵列中删除所有实例

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

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

有两种主要方法:

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

  2. deletedelete anArray[index];

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

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

您还可以期望在使用 delete 后索引号中出现空洞,例如,最终可能会具有使用 delete 之前的索引 1、3、4、8、9 和 11,以及长度。在这种情况下,所有索引的for循环都会崩溃,因为索引不再是顺序的。

如果由于某种原因而被迫使用delete ,那么当您需要遍历数组时,应for each循环使用delete 。实际上,如果可能,请始终避免使用索引for循环。这样,代码将更健壮,并且不易出现索引问题。

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)

无需使用indexOfsplice 。但是,如果只想删除一个元素,它的性能会更好。

查找并移动(移动):

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;
}

使用indexOfsplice (indexof):

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

仅使用splice (splice):

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

在具有 1000 个元素的数组的 nodejs 上的运行时(平均运行 10000 次以上):

indexof大约比move慢 10 倍。即使通过删除对splice 中的 indexOf的调用进行了改进,它的性能也比move差。

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

这提供了谓词而不是值。

注意:它将更新给定的数组,并返回受影响的行。

用法

var removed = helper.removeOne(arr, row => row.id === 5 );

var removed = helper.remove(arr, row => row.name.startsWith('BMW'));

定义

var helper = {

    // Remove and return the first occurrence

    removeOne: function(array, predicate) {
        for (var i = 0; i < array.length; i++) {
            if (predicate(array[i])) {
                return array.splice(i, 1);
            }
        }
    },

    // Remove and return all occurrences

    remove: function(array, predicate) {
        var removed = [];

        for (var i = 0; i < array.length;) {

            if (predicate(array[i])) {
                removed.push(array.splice(i, 1));
                continue;
            }
            i++;
        }
        return removed;
    }
};

John Resig 发布了一个很好的实现

// Array Remove - By John Resig (MIT Licensed)
Array.prototype.remove = function(from, to) {
  var rest = this.slice((to || from) + 1 || this.length);
  this.length = from < 0 ? this.length + from : from;
  return this.push.apply(this, rest);
};

如果您不想扩展全局对象,则可以执行以下操作:

// Array Remove - By John Resig (MIT Licensed)
Array.remove = function(array, from, to) {
    var rest = array.slice((to || from) + 1 || array.length);
    array.length = from < 0 ? array.length + from : from;
    return array.push.apply(array, rest);
};

但是,我发布此消息的主要原因是为了警告用户不要该页面的评论(2007 年 12 月 14 日)中建议的替代实现:

Array.prototype.remove = function(from, to){
  this.splice(from, (to=[0,from||1,++to-from][arguments.length])<0?this.length+to:to);
  return this.length;
};

一开始它似乎运行良好,但是经过一个痛苦的过程,我发现当尝试删除数组中倒数第二个元素时它失败了。例如,如果您有一个包含 10 个元素的数组,并尝试使用此元素删除第 9 个元素:

myArray.remove(8);

您最终得到一个 8 元素数组。不知道为什么,但是我确认 John 的原始实现没有这个问题。