在JavaScript中删除数组元素-删除与拼接

在数组元素上使用#0操作符与使用#1方法有什么区别?

例如:

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

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

1610858 次浏览

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

下面的代码将显示“a”、“b”、“未定义”、“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]);}

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

#0实际删除元素,重新索引数组并更改其长度。

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

Core JavaScript 1.5参考>运算符>特殊运算符>删除运算符

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

splice将使用数字索引。

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

例子:

delete myArray['text1'];

Array.remove()方法

johnresig,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 arrayarray.remove(1);// Remove the second-to-last item from the arrayarray.remove(-2);// Remove the second and third items from the arrayarray.remove(1,2);// Remove the last and second-to-last items from the arrayarray.remove(-2,-1);

约翰的网站

我在试图理解如何从数组中删除元素的每一次出现时偶然发现了这个问题。splice中的这是个对比delete用于从items数组中删除每个'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"]​

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

你可以通过建立一个新的数组来做到这一点。例如

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

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

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

如果你可以使用像切片()这样更快的东西,那就太好了,但它不会重新索引。有人知道更好的方法吗?


实际上,您可能可以按照以下方式执行它,这可能更有效,性能方面:

reindexArray : function( array ){var index = 0;                          // The index where the element should befor( 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)},

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

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

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

你可以用这样的东西

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]

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'];//返回结果:

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

来自节点终端的示例:

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

这是一个通过索引删除数组中一项的函数,使用切片,它将arr作为第一个参数,将要删除的成员的索引作为第二个参数。如您所见,它实际上删除了数组的成员,并将数组长度减少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.length4> var arrayRemoveIndex = require("./lib/array_remove_index");> var newArray = arrayRemoveIndex(arr,arr.indexOf('c'))> newArray[ 'a', 'b', 'd' ] // c ya later> newArray.length3

请注意,这不会在一个包含dupes的数组中工作,因为indexOf("c")只会获得第一个出现,并且只会拼接并删除它找到的第一个"c"。

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

最简单的方法可能是

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 NaNmyArray = _.compact(myArray); ['a', 'c', 'd'];

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

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

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

如上所述,使用splice()似乎是一个完美的选择。

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

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为0,则不删除任何元素。在这种情况下,您应该指定至少一个新元素。如果deleteCount大于数组开始时剩余的元素数,则将删除数组末尾的所有元素。

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

项目1项目2…

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

返回值

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

[…]

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

myArray = myArray.filter(function(item){return item.anProperty != whoShouldBeDeleted});
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 = 3remove_array_value(example_arr, 'banana');

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

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

删除的情况下元素被删除索引保持为空

而在拼接元素被删除的情况下,其余元素的指数相应减少

它们是不同的东西,有不同的目的。

splice是特定于数组的,当用于删除时,从数组中删除条目将所有先前的条目向上移动以填补空白。(它也可以用于插入条目,或同时插入两者。)splice将更改数组的length(假设它不是无操作调用: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);            // 5a.splice(0, 1);console.log(a.length);            // 4console.log(a[0]);                // "b"

console.log("Using `delete`");var a = ["a", "b", "c", "d", "e"];console.log(a.length);            // 5delete a[0];console.log(a.length);            // still 5console.log(a[0]);                // undefinedconsole.log("0" in a);            // falseconsole.log(a.hasOwnProperty(0)); // false

console.log("Setting to `undefined`");var a = ["a", "b", "c", "d", "e"];console.log(a.length);            // 5a[0] = undefined;console.log(a.length);            // still 5console.log(a[0]);                // undefinedconsole.log("0" in a);            // trueconsole.log(a.hasOwnProperty(0)); // true


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

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

  1. 使用plice()

    arrayObject.splice(index, 1);

  2. 使用删除

    delete arrayObject[index];

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

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

或者我在Angular2中使用的

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

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

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

让我们先删除:

delete arr[1];

这就是结果:

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

空的!让我们得到它:

arr[1]; //undefined

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

让我们重置我们的数组并在这次使用plice:

arr.splice(1, 1);

这就是这次的结果:

[1, 3, 4, 5];

正如你看到的数组长度改变了,现在arr[1]3

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

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

拼接:实际删除元素,重新索引数组,并更改长度

删除最后一个元素

arrName.pop();

从first中删除元素

arrName.shift();

从中间删除

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

从最后删除一个元素

arrName.splice(-1);

使用数组索引号删除

 delete arrName[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。

其他人已经正确地将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实际上占用了堆内存。

但是,如果您还将ary项目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的观点,我没有看到任何人在任何地方提到。

如果你有小数组,你可以使用filter

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

性能

关于功能差异已经有很多很好的答案-所以在这里我想专注于性能。今天(2020.06.25)我对Chrome83.0、Safari13.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)}

输入图片描述

详情

我为解决方案执行以下测试ABCDE(我的)

  • 对于小数组(4个元素)-您可以运行test这里
  • 对于大数组(1M元素)-您可以运行test这里

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

Example results for Chrome

enter image description here

保持简单:-

当您为数组中的任何元素删除时,它会删除提及的位置的值并使其为空/未定义,但该位置存在于数组中。

var arr = [1, 2, 3 , 4, 5];
function del() {delete arr[3];console.log(arr);}del(arr);

拼接原型中,参数如下。//arr.splice(开始删除的位置,要删除的项目数)

var arr = [1, 2, 3 , 4, 5];
function spl() {arr.splice(0, 2);// arr.splice(position to start the delete , no. of items to delete)console.log(arr);}spl(arr);

我有两种方法。

简单一:

arr = arr.splice(index,1)

第二张:

arr = arr.filter((v,i)=>i!==index)

第二个的优点是你可以删除一个值(所有,而不仅仅是像大多数一样的第一个实例)

arr = arr.filter((v,i)=>v!==value)