提问人:lYriCAlsSH 提问时间:2/1/2009 最后编辑:Kamil KiełczewskilYriCAlsSH 更新时间:6/1/2022 访问量:1652905
在 JavaScript 中删除数组元素 - delete vs splice
Deleting array elements in JavaScript - delete vs splice
问:
在数组元素上使用 delete
运算符与使用 Array.splice
方法有什么区别?
例如:
myArray = ['a', 'b', 'c', 'd'];
delete myArray[1];
// or
myArray.splice (1, 1);
如果我可以像删除对象一样删除数组元素,为什么还要使用 splice 方法?
答:
由于 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]);
}
评论
myArray.splice(2,1)
delete
将删除 Object 属性,但不会重新索引数组或更新其长度。这使得它看起来好像是未定义的:
> myArray = ['a', 'b', 'c', 'd']
["a", "b", "c", "d"]
> delete myArray[0]
true
> myArray[0]
undefined
请注意,它实际上并没有设置为值,而是从数组中删除了该属性,使其看起来未定义。Chrome 开发工具通过在记录数组时进行打印来明确这种区别。undefined
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"]
评论
delete
delete myArray[0]
splice
delete myArray[0]
myArray[0] = undefined
undefined
empty
undefined
undefined
empty
empty
摘自 Core JavaScript 1.5 参考 > 运算符 > 特殊运算符 > 删除运算符:
删除数组元素时, 数组长度不受影响。为 例如,如果删除 A[3],则 A[4] 为 仍然是 a[4] 和 a[3] 未定义。这 即使删除最后一个,也会保留 元素(删除 a[a.length-1])。
splice
将使用数字索引。
而可用于其他类型的指数。delete
例:
delete myArray['text1'];
评论
arr[2]
arr
arr['x']
x
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);
评论
[1,2,3].slice('1'); // =[2,3]
var rest = this.slice(parseInt(to || from) + 1 || this.length);
this.push.apply(this, rest)
for(var i in array)
我在试图了解如何从 Array 中删除每个元素时偶然发现了这个问题。以下是从 Array 中删除每个 Array 的比较。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"]
如果要迭代一个大型数组并有选择地删除元素,则每次删除都调用 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)
},
评论
可能还值得一提的是,拼接仅适用于数组。(不能依赖对象属性来遵循一致的顺序。
要从对象中删除键值对,delete 实际上是您想要的:
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]
评论
slice
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'];
评论
delete 的行为类似于非现实世界的情况,它只是删除项目,但数组长度保持不变:
来自节点终端的示例:
> var arr = ["a","b","c","d"];
> delete arr[2]
true
> arr
[ 'a', 'b', , 'd', 'e' ]
这是一个通过索引删除数组项的函数,使用 slice(),它将 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.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”。
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 NaN
myArray = _.compact(myArray); ['a', 'c', 'd'];
希望这会有所帮助。 参考: https://lodash.com/docs#compact
评论
compact
myArray.filter(function(n){return n;})
如果要删除的元素位于中间(假设我们要删除 'c',其索引为 1),则可以使用:
var arr = ['a','b','c'];
var indexToDelete = 1;
var newArray = arr.slice(0,indexToDelete).combine(arr.slice(indexToDelete+1, arr.length))
如上所述,使用似乎是一个完美的选择。Mozilla的文档:splice()
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 为 0,则不删除任何元素。在这种情况下,应至少指定一个新元素。如果 deleteCount 大于数组中从开始开始的元素数,则数组末尾的所有元素都将被删除。
如果省略 deleteCount,则 deleteCount 将等于
(arr.length - start).
项目 1、项目 2、...
要添加到数组中的元素,从起始索引开始。如果未指定任何元素,则只会从数组中删除元素。
splice()
返回值
包含已删除元素的数组。如果只删除一个元素,则返回一个元素的数组。如果未删除任何元素,则返回一个空数组。
[...]
为什么不直接过滤呢?我认为这是在js中考虑数组的最清晰方法。
myArray = myArray.filter(function(item){
return item.anProperty != whoShouldBeDeleted
});
评论
delete
slice
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
删除 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); // 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
* (这是我贫血的小博客上的一篇文章)
评论
目前有两种方法可以做到这一点
使用 splice()
arrayObject.splice(index, 1);
使用 delete
delete arrayObject[index];
但是我总是建议对数组对象使用 splice 对对象使用拼接,对对象属性使用 delete,因为 delete 不会更新数组长度。
对于那些想要使用 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
所以意味着只是删除了值,它现在是未定义的,所以长度是相同的,它也将返回 true......
让我们重置我们的数组,这次用拼接来做:
arr.splice(1, 1);
这是这次的结果:
[1, 3, 4, 5];
如您所见,数组长度已更改,现在是 3 ...arr[1]
此外,这将返回数组中已删除的项目,在本例中为...[3]
delete:delete 将删除对象属性,但不会重新编制索引 数组或更新其长度。这使它看起来好像是 定义:
拼接:实际上删除元素,重新索引数组,并更改 它的长度。
删除上一个元素
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];
通过在应用运算符和方法后记录每个数组的长度,可以看出差异。例如: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
运算符从数组中删除元素,但元素的“占位符”仍然存在。 已被删除,但它仍然占用数组中的空间。因此,数组的长度仍为 5。delete
oak
splice() 方法
var trees = ['redwood', 'bay', 'cedar', 'oak', 'maple'];
trees.splice(3,1);
console.log(trees); // ["redwood", "bay", "cedar", "maple"]
console.log(trees.length); // 4
该方法还完全删除了目标值和“占位符”。 已被移除,以及它曾经在阵列中占用的空间。数组的长度现在为 4。splice()
oak
评论
其他人已经适当地与 .delete
splice
另一个有趣的比较是 vs :删除的数组项使用的内存比刚刚设置为delete
undefined
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-item(而不仅仅是将其设置为 ),则代码将缓慢完成: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)我对Chrome 83.0,Safari 13.1和Firefox 77.0进行了测试,以寻找有问题的解决方案以及所选答案
结论
- (B) 解决方案适用于小型和大型阵列
splice
- (A) 解决方案对于大型阵列来说速度最快,对于小型阵列来说,中型阵列速度更快
delete
- (E) 解决方案在 Chrome 和 Firefox 上对于小型阵列最快(但在 Safari 上最慢,对于大型阵列最慢)
filter
- 解决方案 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)}
详
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 的示例结果
保持简单:-
当您删除数组中的任何元素时,它将删除提到的位置的值,并使其为空/未定义,但该位置存在于数组中。
var arr = [1, 2, 3 , 4, 5];
function del() {
delete arr[3];
console.log(arr);
}
del(arr);
其中,与 splice prototype 中的参数一样,参数如下。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)
评论
.splice
delete
Array.prototype.splice