在JavaScript中删除数组元素-Delete与Splice


1333

是什么使用之间的差值delete算子阵列元件上,而不是使用Array.splice方法

例如:

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

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

如果可以像删除对象一样删除数组元素,为什么还要使用splice方法?


3
对于.splicein循环,请看以下问题:在javascript中从数组中删除
罗伯W

6
@andynormancx是的,但是这个答案是在第二天发布的,并获得了更多的选票-我想最好写出来,一定是这样。
卡米洛·马丁

@andynormancx —似乎不完全相同。您链接的问题基本上是在问为什么从数组中删除元素(从而使其稀疏)不会减少其长度。这个问题要求delete和之间的区别Array.prototype.splice
chharvey

@chharvey同意,更重要的是,尽管9年前已经发布了这个问题!让我感到老去回到这里评论
andynormancx

Answers:


1692

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

> myArray = ['a', 'b', 'c', 'd']
  ["a", "b", "c", "d"]
> delete myArray[0]
  true
> myArray[0]
  undefined

请注意,实际上并没有将其设置为value 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"]

74
实际上,delete 确实会删除该元素,但不会为数组重新索引或更新其长度(由于长度始终是最高索引+1,因此前者已经暗示了这一点)。
Felix Kling 2012年

3
JSlint不喜欢这样的delete myArray[0]语法:“需要一个运算符,而看到了'delete'。splice建议使用。
Eye

21
@Eye:实际上,JSLint只是在抱怨前一行缺少分号。而且您真的不能互相推荐,因为它们做的事情完全不同……
Ry-

3
“在这种情况下,删除只会将元素设置为undefined:”不,那完全是错误的。delete myArray[0]和之间有根本的区别myArray[0] = undefined。在前一种情况下,该属性将从数组对象中完全删除。在第二种情况下,该属性保留,值为undefined
TJ Crowder

1
仅供参考,Chrome开发者工具会显示关键字,empty而不是undefined提高实际删除(或未初始化)的数组元素与实际值为的元素之间的区别undefined。请注意,正如我所说的,我的意思是它仅显示empty,而不引用称为的实值empty(不存在)。
chharvey

340

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

约翰的网站


4
+1对于Array.remove()。但是,不满意传递字符串参数(不同于大多数Array方法,例如[1,2,3].slice('1'); // =[2,3]),因此将其更改为更安全var rest = this.slice(parseInt(to || from) + 1 || this.length);
Richard Inglis 2012年

1
@ tomwrong,javascript中没有线程,该函数执行this.push.apply(this, rest),然后返回它返回的值
Billy 2013年

59
这根本无法回答问题。
Ry-

16
为什么不只使用splice()?该函数的名称,参数名称和结果并不明显。我的建议是只使用splice(index,length)-(请参阅Andy Hume的答案)
auco

3
上面提供的功能按说明工作,但是在循环遍历数组时会产生有害的副作用for(var i in array)。我已经删除了它,而是使用了拼接。
alexykot

104

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

以下代码将显示“ 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]);
}

11
很好的示例,除了第二个示例中使用1,1的歧义外-第一个1表示数组中开始拼接的索引,第二个1表示要删除的元素数。因此,要从原始数组中删除“ c”,请使用myArray.splice(2,1)
iancoleman 2012年

68

在尝试了解如何从数组中删除元素的每次出现时,我偶然发现了这个问题。这里有一个比较splice,并delete去除所有的'c'items阵列。

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


10

splice 将与数字索引一起使用。

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

例:

delete myArray['text1'];

9
当您说“任何其他类型的索引”时,您不再在谈论数组,而是在谈论对象,这是OP所要解决的问题。
Yi Jiang

2
@YiJiang:数组是对象。个性化就是属性。没有区别。
Bergi 2012年

9

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

要从对象中删除键值对,删除实际上是您想要的:

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

delete不会重新排列数组键,因此:var arr = [1,2,3,4,5]; 删除arr [3]; for(var i = 0; i <= arr.length; i ++)console.log(arr [i]); 将显示出意外的结果。
克里斯蒂安·威廉姆斯

这是真的。因此,除非要在该位置保留未定义的项目,否则不要在数组的键上使用delete!我最初添加此注释是为了包括正确使用delete的参考。
jtrick

但是为什么删除会引发意外结果?
亚历克斯

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

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

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


8

如上所述,使用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, ...)

参量

开始

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

deleteCount

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

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

item1,item2,...

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

返回值

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

[...]


@downvoter:为什么要投票?在乎解释,还是不?
serv-inc

7

delete的行为类似于非现实情况,它只是删除项目,但数组长度保持不变:

来自节点终端的示例:

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

这是一个使用slice()通过索引删除数组项的函数,它将arr作为第一个arg,将要删除的成员的索引作为第二个参数。如您所见,它实际上删除了数组的成员,并将数组长度减少了1

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

上面的函数所做的是将所有成员移到索引,然后将所有成员移到索引之后,并将它们连接在一起,然后返回结果。

这是一个使用上面的函数作为节点模块的示例,看到终端将很有用:

> 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

请注意,这对一个包含重复项的数组将不起作用,因为indexOf(“ c”)只会得到第一个出现,并且只能剪接并删除找到的第一个“ c”。


6

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

您可以通过构建一个新数组来做到这一点。例如

function reindexArray( array )
{
       var result = [];
        for( var key in array )
                result.push( array[key] );
        return result;
};

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

请注意,您不需要检查“未定义”条目,因为它们实际上并不存在,并且for循环不会返回它们。这是阵列打印的结果,将其显示为未定义。它们似乎不存在于内存中。

如果您可以使用诸如slice()之类的更快的方法,但是它不会重新索引,那将是很好的。有人知道更好的方法吗?


实际上,您可能可以按以下方式进行,这可能会更高效,更明智地执行以下操作:

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)
},

我相信++ index; 需要在“如果”之外发生。进行编辑
mishal153

6

你可以用这样的东西

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]


这比slice您具有功能背景(虽然效率可能较低)更直观。
jethro

3

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

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

那么具有数百个(如果不是数千个)记录的阵列又需要删除其中的3个呢?
乔尔·埃尔南德斯

好点子。我对长度不超过200或300的稀疏数组使用此方法,并且性能很好。但是,我认为,如果必须管理更大的数组,则最好使用下划线之类的库。
Asqan

1
然而,似乎更漂亮比deleteslice给我。
Juneyoung,Oh,2008年

3

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

删除运算符

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

splice()方法会完全删除目标值 “占位符”。oak已被删除,以及它在阵列中占用的空间。数组的长度现在为4。


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

例:

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

香蕉被删除,数组长度= 2


2

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

splice是阵列特异性和,用于删除时,删除该数组项移动的所有以前的条目,以填补该间隙。(它也可以用于插入条目,或同时插入两个条目。)splice将更改length数组的大小(假设它不是no-op调用:)theArray.splice(x, 0)

delete不是特定于数组的;它设计用于对象:它从使用对象的对象中删除属性(键/值对)。它仅适用于数组,因为JavaScript 中的标准(例如,非类型化)数组根本不是真正的数组 *,它们是对某些属性进行特殊处理的对象,例如名称为“数组索引”的对象(定义为字符串名称“ ...其数值i在范围内+0 ≤ i < 2^32-1”)和length。当您使用delete删除数组条目时,它所做的就是删除该条目。它不会移动其他条目来填补空白,因此数组变为“稀疏”(某些条目完全丢失)。它对没有影响length

该问题的两个当前答案错误地指出使用delete“将条目设置为undefined”。那是不对的。它完全删除条目(属性),从而留下空白。

让我们用一些代码来说明不同之处:

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"

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

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


* (这是我贫乏的小博客上的帖子)


2

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

  1. 使用splice()

    arrayObject.splice(index, 1);

  2. 使用删除

    delete arrayObject[index];

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


1

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

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

让我们先删除:

delete arr[1];

结果是:

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

空!让我们得到它:

arr[1]; //undefined

因此,意味着仅删除了该值,并且现在未定义该值,因此长度相同,并且将返回true

让我们重置数组,这次用拼接来完成它:

arr.splice(1, 1);

这是这次的结果:

[1, 3, 4, 5];

如您所见,数组长度已更改,现在arr[1]3 ...

同样,这将返回数组中已删除的项目,[3]在这种情况下...


1

其他人已经比较正常delete使用splice

与另一个有趣的比较:deleteundefined刚设置的数组项相比,删除的数组项使用的内存更少undefined;

例如,此代码不会完成:

let y = 1;
let ary = [];
console.log("Fatal Error Coming Soon");
while (y < 4294967295)
{
    ary.push(y);
    ary[y] = undefined;
    y += 1;
}
console(ary.length);

它产生此错误:

FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory.

因此,您可以看到undefined实际上占用了堆内存。

但是,如果您还delete使用ary项目(而不是仅将其设置为undefined),则代码将慢慢完成:

let x = 1;
let ary = [];
console.log("This will take a while, but it will eventually finish successfully.");
while (x < 4294967295)
{
    ary.push(x);
    ary[x] = undefined;
    delete ary[x];
    x += 1;
}
console.log(`Success, array-length: ${ary.length}.`);

这些是极端的例子,但它们delete说明了我从未见过有人提及的地方。



0

最简单的方法可能是

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


1
如果有人compact偶然发现这个关于……的疑问,那就不用lodash了。试试myArray.filter(function(n){return n;})
dat

0

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

或者像我在Angular2中使用的

import { without } from 'lodash';
...
myArray = without(myArray, itemToRemove);
...

0

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

splice:实际上删除元素,为数组重新索引,并更改其长度。

从最后删除元素

arrName.pop();

首先删除元素

arrName.shift();

从中间删除

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

Ex: arrName.splice(1,1);

从最后删除一个元素

arrName.splice(-1);

使用数组索引号删除

 delete arrName[1];

0

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

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

0

IndexOf还接受引用类型。假设以下情况:

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

不同的是:

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
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'];


@ChrisDennis为什么?(没有讽刺或恶意的意图,这是一个真诚的问题)
克里斯·比尔

除了这个事实,这个答案并没有解决OP的问题
克里斯·比尔
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.