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

时间:2009-02-01 11:11:16

标签: javascript arrays array-splice delete-operator

在数组元素上使用the delete operator而不是使用the Array.splice method有什么区别?

例如:

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

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

如果我能用对象删除数组元素,为什么甚至有拼接方法?

27 个答案:

答案 0 :(得分:1644)

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

答案 1 :(得分:330)

Array.remove()方法

John Resig ,jQuery的创建者创建了一个非常方便的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's website

答案 2 :(得分:102)

因为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]);
}

答案 3 :(得分:65)

我在试图理解如何从数组中删除每个元素时偶然发现了这个问题。 splicedelete的{​​{3}}用于从'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"]
​

答案 4 :(得分:14)

来自 Core JavaScript 1.5 Reference > Operators > Special Operators > delete Operator

  

删除数组元素时,   数组长度不受影响。对于   例如,如果删除[3],则[4]为   仍然是[4]和[3]未定义。这个   即使你删除了最后一个也保持   数组的元素(删除   一个[则为a.length-1])。

答案 5 :(得分:9)

splice将使用数字索引。

delete可用于对抗其他类型的指数..

示例:

delete myArray['text1'];

答案 6 :(得分:9)

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

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

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

答案 7 :(得分:8)

如上所述,使用splice()似乎非常合适。 Documentation at 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大于从start开始的数组中剩余的元素数,那么通过数组末尾的所有元素都将被删除。

     

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

     

item1,item2,...

     

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

     

返回值

     

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

     

[...]

答案 8 :(得分:7)

删除就像非现实世界的情况一样,只是删除项目,但数组长度保持不变:

来自节点终端的

示例:

> 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

请注意,这对于一个带有dupes的数组不起作用,因为indexOf(&#34; c&#34;)只会获得第一次出现,并且只能拼接并删除第一个&#34; c&# 34;它找到了。

答案 9 :(得分:7)

删除Vs拼接

从数组中删除项目时

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

如果删除 元素已删除索引仍为空

如果拼接元素被删除,其余元素的索引会相应减少

答案 10 :(得分:6)

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

您可以通过构建新数组来实现。 e.g

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

答案 11 :(得分:5)

你可以使用这样的东西

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]

答案 12 :(得分:2)

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

  1. 使用splice()

    arrayObject.splice(index, 1);

  2. 使用删除

    delete arrayObject[index];

  3. 但我总是建议对数组对象使用splice并删除对象属性,因为delete不会更新数组长度。

答案 13 :(得分:2)

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

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

答案 14 :(得分: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');

banana被删除,数组长度= 2

答案 15 :(得分:2)

他们是不同目的的不同事物。

splice是特定于数组的,当用于删除时,会删除数组中的条目,而会移动所有先前的条目以填补空白。 (它也可以用于同时插入条目或两者。)splice将更改数组的length(假设它不是无操作调用:theArray.splice(x, 0)

delete不是特定于数组的;它设计用于对象:它从您使用它的对象中删除属性(键/值对)。它仅适用于数组,因为JavaScript aren't really arrays at all *中的标准(例如,非类型)数组,它们是对某些属性具有特殊处理的对象,例如名称为“数组索引”的那些(即{{ 3}}作为字符串名称“......其数值i在[{1}}”)和+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

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

答案 16 :(得分:1)

性能

关于功能差异,已经有很多不错的答案-因此,在这里我想着重介绍性能。今天(2020.06.25),我针对Chrome 83.0,Safari 13.1和Firefox 77.0进行了测试,以解决有问题的解决方案以及所选择的答案

结论

  • splice(B)解决方案对于大小阵列都很快速
  • delete(A)解决方案对于大型阵列来说是最快的,对于小型阵列来说是最快的
  • filter(E)解决方案在小型阵列的Chrome和Firefox上最快(但在Safari上最慢,在大型阵列上最慢)
  • 解决方案D相当慢
  • 解决方案C不适用于Chrome和Safari中的大型阵列
    function C(arr, idx) {
      var rest = arr.slice(idx + 1 || arr.length);
      arr.length = idx < 0 ? arr.length + idx : idx;
      arr.push.apply(arr, rest);
      return arr;
    }
    
    
    // Crash test
    
    let arr = [...'abcdefghij'.repeat(100000)]; // 1M elements
    
    try {
     C(arr,1)
    } catch(e) {console.error(e.message)}

enter image description here

详细信息

我对解决方案执行以下测试 A B C D E(我的)

  • 对于小数组(4个元素)-您可以运行测试HERE
  • 对于大数组(1M个元素)-您可以运行测试HERE

function A(arr, idx) {
  delete arr[idx];
  return arr;
}

function B(arr, idx) {
  arr.splice(idx,1);
  return arr;
}

function C(arr, idx) {
  var rest = arr.slice(idx + 1 || arr.length);
  arr.length = idx < 0 ? arr.length + idx : idx;
  arr.push.apply(arr, rest);
  return arr;
}

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

function E(arr,idx) {
  return arr.filter((a,i) => i !== idx);
}

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

[A,B,C,D,E].map(f => console.log(`${f.name} ${JSON.stringify(f([...myArray],1))}`));
This snippet only presents used solutions

Chrome的示例结果

enter image description here

答案 17 :(得分:1)

在应用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。

答案 18 :(得分: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] ...

答案 19 :(得分:0)

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

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

答案 20 :(得分:0)

对于那些想要使用http://www.enavigo.com/2012/01/04/enabling-oracle-oci8-php-extension-on-os-x-snow-leopard/的人可以使用: CREATE DATABASE IF NOT EXISTS master; USE DATABASE master; DROP ASSEMBLY IF EXISTS [ExtPython]; CREATE ASSEMBLY IF NOT EXISTS [ExtPython] FROM @"/usqlext/assembly/python/ExtPy.dll" WITH ADDITIONAL_FILES = ( @"/usqlext/assembly/python/ExtPy.pdb", @"/usqlext/assembly/python/UsqlPythonInvokePackage.zip", @"/usqlext/assembly/python/UsqlPythonDeployPackage.zip", @"/usqlext/assembly/python/version.python" );

或者我在Angular2中使用

myArray = _.without(myArray, itemToRemove)

答案 21 :(得分: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

答案 22 :(得分:0)

  

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

     

拼接:实际上是删除元素,为数组重新索引并进行更改   它的长度。

从最后删除元素

created_at:[* TO NOW]

从第一个

删除元素
arrName.pop();

从中间删除

arrName.shift();

从最后删除一个元素

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

Ex: arrName.splice(1,1);

使用数组索引号删除

arrName.splice(-1);

答案 23 :(得分: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

答案 24 :(得分:0)

其他人已经将deletesplice进行了比较。

另一个有趣的比较是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(而不是仅将其设置为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,我从未见过有人提及。

答案 25 :(得分:0)

如果阵列较小,则可以使用filter

myArray = ['a', 'b', 'c', 'd'];
myArray = myArray.filter(x => x !== 'b');

答案 26 :(得分:-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 = [&#39; b&#39;,&#39; c&#39;,&#39; d&#39;];