关于在JavaScript中删除数组元素:在JavaScript中删除数组元素 – 删除vs splice

Deleting array elements in JavaScript - delete vs splice

在数组元素上使用delete运算符与使用Array.splice方法有什么区别?

例如:

1
2
3
4
5
myArray = ['a', 'b', 'c', 'd'];

delete myArray[1];
//  or
myArray.splice (1, 1);

如果我能像删除对象那样删除数组元素,为什么还要使用拼接方法呢?


delete将删除对象属性,但不会重新索引数组或更新其长度。这使得它看起来像是未定义的:

1
2
3
4
5
6
> myArray = ['a', 'b', 'c', 'd']
  ["a","b","c","d"]
> delete myArray[0]
  true
> myArray[0]
  undefined

注意,它实际上并没有设置为undefined的值,而是从数组中删除了该属性,使其看起来未定义。chrome dev工具通过在记录数组时打印empty来明确这一区别。

1
2
3
4
> myArray[0]
  undefined
> myArray
  [empty,"b","c","d"]

myArray.splice(start, deleteCount)实际上删除了元素,重新索引了数组,并更改了数组的长度。

1
2
3
4
5
6
> myArray = ['a', 'b', 'c', 'd']
  ["a","b","c","d"]
> myArray.splice(0, 2)
  ["a","b"]
> myArray
  ["c","d"]


array.remove()方法

jquery的创建者john resig创建了一个非常方便的Array.remove方法,我总是在项目中使用它。

1
2
3
4
5
6
// 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);
};

下面是一些如何使用它的例子:

1
2
3
4
5
6
7
8
// Remove the second item from the array
array.remove(1);
// Remove the second-to-last item from the array
array.remove(-2);
// Remove the second and third items from the array
array.remove(1,2);
// Remove the last and second-to-last items from the array
array.remove(-2,-1);

约翰网站


因为delete只从数组中的元素中删除对象,所以数组的长度不会改变。拼接将删除对象并缩短阵列。

以下代码将显示"A"、"B"、"未定义"、"D"

1
2
3
4
5
myArray = ['a', 'b', 'c', 'd']; delete myArray[2];

for (var count = 0; count < myArray.length; count++) {
    alert(myArray[count]);
}

鉴于这将显示"A"、"B"、"D"

1
2
3
4
5
myArray = ['a', 'b', 'c', 'd']; myArray.splice(2,1);

for (var count = 0; count < myArray.length; count++) {
    alert(myArray[count]);
}


我在试图理解如何从数组中删除元素的每次出现时,偶然发现了这个问题。这里比较了splicedelete,从items数组中删除每个'c'

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var items = ['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd'];

while (items.indexOf('c') !== -1) {
  items.splice(items.indexOf('c'), 1);
}

console.log(items); // ["a","b","d","a","b","d"]

items = ['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd'];

while (items.indexOf('c') !== -1) {
  delete items[items.indexOf('c')];
}

console.log(items); // ["a","b", undefined,"d","a","b", undefined,"d"]
?


从核心javascript 1.5参考>操作员>特殊操作员>删除操作员:

When you delete an array element, the
array length is not affected. For
example, if you delete a[3], a[4] is
still a[4] and a[3] is undefined. This
holds even if you delete the last
element of the array (delete
a[a.length-1]).


splice将使用数字索引。

delete可用于其他类型的指数。

例子:

1
delete myArray['text1'];


可能还值得一提的是,拼接只适用于数组。(不能依赖对象属性来遵循一致的顺序。)

要从对象中删除键值对,实际上需要删除:

1
2
delete myObj.propName;     // , or:
delete myObj["propName"];  // Equivalent.


如前所述,使用splice()似乎是一种完美的匹配。Mozilla的文档:

The splice() method changes the content of an array by removing existing elements and/or adding new elements.

1
2
3
4
5
6
7
var myFish = ['angel', 'clown', 'mandarin', 'sturgeon'];

myFish.splice(2, 0, 'drum');
// myFish is ["angel","clown","drum","mandarin","sturgeon"]

myFish.splice(2, 1);
// myFish is ["angel","clown","mandarin","sturgeon"]

Syntax

1
2
3
array.splice(start)
array.splice(start, deleteCount)
array.splice(start, deleteCount, item1, item2, ...)

参数开始

开始更改数组的索引。如果大于数组的长度,则实际的起始索引将设置为数组的长度。如果为负,则从结尾开始许多元素。

删除程序

一个整数,指示要删除的旧数组元素的数目。如果deleteCount为0,则不删除任何元素。在这种情况下,您应该至少指定一个新元素。如果deleteCount大于数组中从开始时剩余的元素数,则将删除数组末尾的所有元素。

如果省略deleteCount,则deleteCount将等于(arr.length - start).

第1项,第2项,…

要添加到数组中的元素,从开始索引开始。如果不指定任何元素,splice()将只从数组中删除元素。

返回值

包含已删除元素的数组。如果只删除一个元素,则返回一个元素数组。如果没有删除任何元素,则返回空数组。

[…]

< /块引用>


删除操作类似于非真实情况,它只删除项目,但数组长度保持不变:

节点终端示例:

1
2
3
4
5
> var arr = ["a","b","c","d"];
> delete arr[2]
true
> arr
[ 'a', 'b', , 'd', 'e' ]

下面是一个按索引移除数组项的函数,使用slice(),它将arr作为第一个参数,将要删除的成员的索引作为第二个参数。如您所见,它实际上会删除数组的成员,并将数组长度缩短1

1
2
3
function(arr,arrIndex){
    return arr.slice(0,arrIndex).concat(arr.slice(arrIndex + 1));
}

上面的函数的作用是将所有成员带到索引,以及索引后的所有成员,并将它们连接在一起,然后返回结果。

下面是一个使用上述功能作为节点模块的示例,看到终端将很有用:

1
2
3
4
5
6
7
8
9
10
11
> var arr = ["a","b","c","d"]
> arr
[ 'a', 'b', 'c', 'd' ]
> arr.length
4
> var arrayRemoveIndex = require("./lib/array_remove_index");
> var newArray = arrayRemoveIndex(arr,arr.indexOf('c'))
> newArray
[ 'a', 'b', 'd' ] // c ya later
> newArray.length
3

请注意,在一个数组中使用duple将不起作用,因为indexof("c")只会出现第一次,并且只会拼接并删除它找到的第一个"c"。


删除vs拼接

从数组中删除项时

1
2
var arr = [1,2,3,4]; delete arr[2]; //result [1, 2, 3:, 4]
console.log(arr)

当你剪接时

1
2
var arr = [1,2,3,4]; arr.splice(1,1); //result [1, 3, 4]
console.log(arr);

如果删除,则删除元素,但索引保持为空

而在拼接元素被删除的情况下,其余元素的索引也相应减少。


如果您想迭代一个大数组并有选择地删除元素,那么每次删除都要调用splice()是很昂贵的,因为splice()每次都必须重新索引后续元素。因为数组在javascript中是关联的,所以删除单个元素然后重新索引数组会更有效。

您可以通过构建一个新的数组来实现。例如

1
2
3
4
5
6
7
function reindexArray( array )
{
       var result = [];
        for( var key in array )
                result.push( array[key] );
        return result;
};

但我不认为您可以修改原始数组中的键值,这会更有效-看起来您可能需要创建一个新的数组。

注意,您不需要检查"未定义"条目,因为它们实际上不存在,并且for循环不返回它们。它是数组打印的产物,显示为未定义。它们似乎不存在于记忆中。

如果您可以使用类似slice()的东西,这样会更快,但是它不会重新索引。有人知道更好的方法吗?

实际上,您可能可以按以下方式在适当的位置执行,这可能更高效、更具性能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
reindexArray : function( array )
{
    var index = 0;                          // The index where the element should be
    for( var key in array )                 // Iterate the array
    {
        if( parseInt( key ) !== index )     // If the element is out of sequence
        {
            array[index] = array[key];      // Move it to the correct, earlier position in the array
            ++index;                        // Update the index
        }
    }

    array.splice( index );  // Remove any remaining elements (These will be duplicates of earlier items)
},


你可以用这样的东西

1
2
3
var my_array = [1,2,3,4,5,6];
delete my_array[4];
console.log(my_array.filter(function(a){return typeof a !== 'undefined';})); // [1,2,3,4,6]


1
2
3
4
5
6
7
8
9
10
11
12
13
14
function remove_array_value(array, value) {
    var index = array.indexOf(value);
    if (index >= 0) {
        array.splice(index, 1);
        reindex_array(array);
    }
}
function reindex_array(array) {
   var result = [];
    for (var key in array) {
        result.push(array[key]);
    }
    return result;
}

例子:

1
2
var example_arr = ['apple', 'banana', 'lemon'];   // length = 3
remove_array_value(example_arr, 'banana');

删除香蕉,数组长度=2


它们是具有不同目的的不同事物。

splice是特定于数组的,用于删除时,从数组中删除条目,并向上移动所有以前的条目以填补空白。(它也可以用来插入条目,或者同时插入两者。)splice将更改数组的length(假设它不是一个no-op调用:theArray.splice(x, 0))。

delete不是特定于数组的;它设计用于对象:它从使用它的对象中删除一个属性(键/值对)。它只适用于数组,因为javascript中的标准(例如非类型)数组根本不是数组*,它们是对某些属性具有特殊处理的对象,例如那些名称为"数组索引"(定义为字符串名称"…其数值i+0 ≤ i < 2^32-1length的范围内)的对象。当您使用delete删除一个数组条目时,它所做的就是删除该条目;它不会在后面移动其他条目来填补空白,因此数组变得"稀疏"(完全缺少一些条目)。它对length没有影响。

目前对这个问题的一些回答错误地指出,使用delete将条目设置为undefined。那不正确。它完全删除条目(属性),留下一个空白。

让我们用一些代码来说明区别:

1
2
3
4
5
6
console.log("Using `splice`:");
var a = ["a","b","c","d","e"];
console.log(a.length);            // 5
a.splice(0, 1);
console.log(a.length);            // 4
console.log(a[0]);                //"b"

1
2
3
4
5
6
7
8
console.log("Using `delete`");
var a = ["a","b","c","d","e"];
console.log(a.length);            // 5
delete a[0];
console.log(a.length);            // still 5
console.log(a[0]);                // undefined
console.log("0" in a);            // false
console.log(a.hasOwnProperty(0)); // false

1
2
3
4
5
6
7
8
console.log("Setting to `undefined`");
var a = ["a","b","c","d","e"];
console.log(a.length);            // 5
a[0] = undefined;
console.log(a.length);            // still 5
console.log(a[0]);                // undefined
console.log("0" in a);            // true
console.log(a.hasOwnProperty(0)); // true

*(这是我贫血的博客上的一篇文章)


目前有两种方法可以做到这一点

  • 使用剪接()

    arrayObject.splice(index, 1);

  • 使用删除

    delete arrayObject[index];

  • 但我总是建议对数组对象使用拼接,对对象属性使用删除,因为删除不会更新数组长度。


    为什么不过滤呢?我认为这是在JS中考虑数组的最清晰的方法。

    1
    2
    3
    myArray = myArray.filter(function(item){
        return item.anProperty != whoShouldBeDeleted
    });


    应用delete运算符和splice()方法后,通过记录每个数组的长度可以看出差异。例如:

    删除操作符

    1
    2
    3
    4
    5
    var trees = ['redwood', 'bay', 'cedar', 'oak', 'maple'];
    delete trees[3];

    console.log(trees); // ["redwood","bay","cedar", empty,"maple"]
    console.log(trees.length); // 5

    delete运算符从数组中删除元素,但元素的"占位符"仍然存在。oak已被删除,但它仍占用阵列中的空间。因此,数组的长度保持为5。

    拼接()方法

    1
    2
    3
    4
    5
    var trees = ['redwood', 'bay', 'cedar', 'oak', 'maple'];
    trees.splice(3,1);

    console.log(trees); // ["redwood","bay","cedar","maple"]
    console.log(trees.length); // 4

    splice()方法也完全删除了目标值和"占位符"。oak已被移除,以及它在阵列中所占的空间。数组的长度现在为4。


    好吧,假设我们有下面这个数组:

    1
    const arr = [1, 2, 3, 4, 5];

    我们先删除:

    1
    delete arr[1];

    这就是结果:

    1
    [1, empty, 3, 4, 5];

    空!让我们来看看:

    1
    arr[1]; //undefined

    所以意味着只删除了值,现在它还未定义,所以长度是相同的,也会返回真的…

    让我们重新设置阵列,这次使用拼接:

    1
    arr.splice(1, 1);

    这次的结果是:

    1
    [1, 3, 4, 5];

    如你所见,数组长度改变了,arr[1]现在是3…

    此外,在这种情况下,它还将返回数组中的已删除项,该数组是[3]


    最简单的方法可能是

    1
    2
    3
    var myArray = ['a', 'b', 'c', 'd'];
    delete myArray[1]; // ['a', undefined, 'c', 'd']. Then use lodash compact method to remove false, null, 0,"", undefined and NaN
    myArray = _.compact(myArray); ['a', 'c', 'd'];

    希望这有帮助。参考:https://lodash.com/docs compact


    如果要删除的元素位于中间(假设我们要删除"c",其索引为1),则可以使用:

    1
    2
    3
    var arr = ['a','b','c'];
    var indexToDelete = 1;
    var newArray = arr.slice(0,indexToDelete).combine(arr.slice(indexToDelete+1, arr.length))

    对于那些想使用罗达什的人,可以使用:myArray = _.without(myArray, itemToRemove)

    或者像我在安古拉语中使用的那样2

    1
    2
    3
    4
    import { without } from 'lodash';
    ...
    myArray = without(myArray, itemToRemove);
    ...

    delete: delete will delete the object property, but will not reindex
    the array or update its length. This makes it appears as if it is
    undefined:

    splice: actually removes the element, reindexes the array, and changes
    its length.

    从最后删除元素

    1
    arrName.pop();

    从第一个删除元素

    1
    arrName.shift();

    从中间删除

    1
    2
    3
    arrName.splice(starting index,number of element you wnt to delete);

    Ex: arrName.splice(1,1);

    从最后一个元素中删除一个元素

    1
    arrName.splice(-1);

    使用数组索引号删除

    1
     delete arrName[1];

    IndexOf也接受引用类型。假设以下场景:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var arr = [{item: 1}, {item: 2}, {item: 3}];
    var found = find(2, 3); //pseudo code: will return [{item: 2}, {item:3}]
    var l = found.length;

    while(l--) {
       var index = arr.indexOf(found[l])
          arr.splice(index, 1);
       }
       
    console.log(arr.length); //1

    不同的:

    1
    2
    3
    4
    5
    6
    7
    8
    var item2 = findUnique(2); //will return {item: 2}
    var l = arr.length;
    var found = false;
      while(!found && l--) {
      found = arr[l] === item2;
    }

    console.log(l, arr[l]);// l is index, arr[l] is the item you look for

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    function deleteFromArray(array, indexToDelete){
      var remain = new Array();
      for(var i in array){
        if(array[i] == indexToDelete){
          continue;
        }
        remain.push(array[i]);
      }
      return remain;
    }

    myArray = ['a', 'b', 'c', 'd'];
    deleteFromArray(myArray , 0);

    //结果:myarray=['b'、'c'、'd'];