JavaScript中删除数组元素 - delete vs splice

1450

使用delete操作符和使用Array.splice方法在数组元素上的区别是什么?

例如:

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

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

如果我可以像操作对象一样删除数组元素,那为什么还需要splice方法呢?


3
关于在循环中使用 .splice,请参考这个问题:在JavaScript中从数组中删除元素 - Rob W
6
是的,但是这个回答是在之后的一天发布的,并且得到了更多的投票 - 我会说它写得更好,这就是原因。 - Camilo Martin
@andynormancx — 看起来这不是完全重复的问题。你链接的那个问题基本上是在问为什么从数组中删除一个元素(从而使其变得稀疏)不会减少它的长度。而这个问题则是在询问deleteArray.prototype.splice之间的区别。 - chharvey
@chharvey同意,但更重要的是,这个问题怎么可能在9年前发布!让我感到老了,现在又回来评论它。 - andynormancx
《JavaScript:前20年》提到:“JavaScript 1.1添加了delete、typeof和void运算符。在JavaScript 1.1中,delete运算符仅将其变量或对象属性操作数设置为null值。”并且splice被添加到1.2版本中,“数组push、pop、shift、unshift和splice直接模拟了同名的Perl数组函数。” - Qiulang
29个回答

1818

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

> myArray = ['a', 'b', 'c', 'd']
  ["a", "b", "c", "d"]
> delete myArray[0]
  true
> myArray[0]
  undefined
请注意,实际上它并没有设置为值undefined,而是从数组中删除该属性,使其看起来像是未定义。Chrome开发工具通过在记录数组时打印empty来明确这种差异。
> myArray[0]
  undefined
> myArray
  [empty, "b", "c", "d"]

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

> myArray = ['a', 'b', 'c', 'd']
  ["a", "b", "c", "d"]
> myArray.splice(0, 2)
  ["a", "b"]
> myArray
  ["c", "d"]

84
实际上, delete 确实 移除了该元素,但不会重新索引数组或更新其长度(因为由前者已经隐含了长度始终是最高索引+1)。 - Felix Kling
3
JSlint不喜欢delete myArray[0]这种语法,会提示"Expected an operator and instead saw 'delete'."建议使用splice代替。 - esengineer
30
@Eye: 实际上,JSLint只是在抱怨前一行缺少分号。而且你不能真正推荐一个比另一个更好,因为它们执行完全不同的任务... - Ry-
5
在这种情况下,“delete”只会将元素设置为未定义:“No, that is flatly incorrect. There's a fundamental difference between delete myArray[0] and myArray[0] = undefined.在前一种情况下,该属性被完全从数组对象中删除。在第二种情况下,该属性仍然存在,其值为“undefined”。" - T.J. Crowder
2
Chrome开发工具显示关键字“empty”而不是“undefined”,以改善实际删除(或未初始化)数组元素与具有实际值为“undefined”的元素之间的区别。请注意,当我说这个时,我只是指它显示为“empty”,并且不是指称为“empty”的真实值(不存在)。 - chharvey
显示剩余5条评论

351

Array.remove() 方法

jQuery 的创始人 John Resig 创建了一个非常方便的 Array.remove 方法,我在自己的项目中经常使用它。

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

以下是一些使用示例:

// 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);

John的网站


5
对于Array.remove()给予赞赏。然而,与大多数数组方法(例如[1,2,3].slice('1'); // =[2,3])不同,它不能接受字符串类型的参数。因此,更安全的做法是将它改为var rest = this.slice(parseInt(to || from) + 1 || this.length); - Richard Inglis
1
@tomwrong,JavaScript 中没有线程,函数执行 this.push.apply(this, rest),然后返回它返回的值。 - billy
76
这完全没有回答问题。 - Ry-
17
为什么不使用splice()函数?这个函数的名称、参数名和结果并不明显。我的建议是,只需使用splice(index, length)函数(请参见Andy Hume的答案)。 - auco
3
上面提供的函数按照解释的方式工作,但是在使用for(var i in array)循环迭代数组时会产生不必要的副作用。我已经将其删除并改用splice。 - alexykot
显示剩余10条评论

108

因为delete只是从数组中移除对象,所以数组的长度不会改变。而splice则移除对象并缩短数组。

以下代码将显示 "a", "b", "undefined", "d"

myArray = ['a', 'b', 'c', 'd']; delete myArray[2];

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

而这将显示 "a","b","d"

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

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

12
第二个例子存在歧义,但整体是一个很好的例子。其中使用了1,1 - 第一个1表示要开始剪切的数组索引,第二个1是要删除的元素数量。因此,要从原始数组中删除 'c',请使用 myArray.splice(2,1) - iancoleman

77

在尝试理解如何从数组中删除每个元素的情况下,我偶然发现了这个问题。这里进行比较使用splicedeleteitems数组中删除每个'c'

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"]

14

12

如上所述,使用 splice() 方法似乎非常适合。 Mozilla 文档:

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

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"]

语法

(需要翻译的内容在这里)
array.splice(start)
array.splice(start, deleteCount)
array.splice(start, deleteCount, item1, item2, ...)

参数

start

开始修改数组的索引值。如果大于数组长度,实际的起始索引将被设置为数组长度。如果为负数,则从末尾开始那么多个元素。

deleteCount

一个整数,表示要删除的旧数组元素数量。如果deleteCount为0,则不会删除任何元素,此时您应该至少指定一个新元素。如果deleteCount大于从start开始的数组剩余元素数量,则将删除数组到末尾的所有元素。

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

item1, item2, ...

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

返回值

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

[...]


10

splice 可以使用数字索引。

delete 可以用于其他类型的索引。

例子:

delete myArray['text1'];

10
当你说“任何其他类型的指数”时,你不再谈论数组,而是对象,这正是原帖提问的内容。 - Yi Jiang
2
@YiJiang:数组是对象,索引是属性,它们之间没有区别。 - Bergi
@Bergi: arr[2] 是数组 arr 的第三个元素,而 arr['x'] 是对象的属性 x。在实际使用中并没有太大区别,但它们在内部存储方式上是不同的。 - David R Tribble

9
删除与剪接
当您从数组中删除一个项目时

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

当你接合时

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

在删除元素时,如果使用delete,则会删除该元素,但索引仍为空
而使用splice时,元素被删除后,其余元素的索引会相应地减少

9
值得一提的是,splice 只能用于数组。(对象属性不能保证遵循一致的顺序。)
要从对象中移除键值对,您实际上需要使用 delete:
delete myObj.propName;     // , or:
delete myObj["propName"];  // Equivalent.

delete不会重新排列数组键,因此:var arr = [1,2,3,4,5]; delete arr[3]; for (var i = 0; i <= arr.length; i++) console.log(arr[i]);将展示出意想不到的结果。 - Kristian Williams
这是真的。因此,除非您想在该位置留下未定义的项,请勿在数组的键上使用delete!我最初添加了此注释以包括有关正确使用delete的参考。 - jtrick
但是为什么删除操作会抛出意外的结果呢? - Alex

7

使用delete运算符和splice()方法后,可以通过记录每个数组的长度来看到它们之间的区别。例如:

delete 运算符

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。

splice()方法

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

console.log(trees); // ["redwood", "bay", "cedar", "maple"]
console.log(trees.length); // 4
< p > splice() 方法完全删除目标值"占位符"。 oak 已被删除,以及它在数组中所占据的空间。数组的长度现在为 4。


无论性能或任何其他深奥的讨论,删除和切割都不是相同的。当您必须从数组中删除一个元素,使得数组长度反映实际元素数量时,您只有两种选择。最佳答案在这里。 - iGanja

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