如何在 JavaScript 中清空数组?

IT技术 javascript arrays
2021-01-23 00:26:20

有没有办法清空数组,如果可能的话.remove()

例如,

A = [1,2,3,4];

我怎么能清空它?

6个回答

清除现有数组的方法A

方法一

(这是我对这个问题的原始回答)

A = [];

此代码将变量设置A为一个新的空数组。如果您在其他任何地方都没有对原始数组的引用,A这是完美的,因为这实际上创建了一个全新的(空)数组。你应该小心使用这个方法,因为如果你从另一个变量或属性引用了这个数组,原始数组将保持不变。仅当您仅通过其原始变量引用数组时才使用此选项A

这也是最快的解决方案。

此代码示例显示了使用此方法时可能遇到的问题:

var arr1 = ['a','b','c','d','e','f'];
var arr2 = arr1;  // Reference arr1 by another variable 
arr1 = [];
console.log(arr2); // Output ['a','b','c','d','e','f']

方法 2Matthew Crumley建议

A.length = 0

这将通过将其长度设置为 0 来清除现有数组。有人认为这可能不适用于 JavaScript 的所有实现,但事实证明并非如此。它在 ECMAScript 5 中使用“严格模式”时也有效,因为数组的长度属性是读/写属性。

方法 3Anthony建议

A.splice(0,A.length)

Using.splice()将完美运行,但由于该.splice()函数将返回一个包含所有已删除项目的数组,因此它实际上将返回原始数组的副本。基准测试表明,这对性能没有任何影响。

方法4(如建议tanguy_k

while(A.length > 0) {
    A.pop();
}

这个解决方案不是很简洁,它也是最慢的解决方案,与原始答案中引用的早期基准相反。

表现

在清除现有数组的所有方法中,方法 2 和方法 3 在性能上非常相似,并且比方法 4 快很多请参阅此基准测试

正如Diadistis下面回答指出的那样,用于确定上述四种方法性能的原始基准是有缺陷的。原始基准重用已清除的数组,因此第二次迭代清除已经为空的数组。

以下基准修复了这个缺陷:http : //jsben.ch/#/hyj65它清楚地表明方法#2(长度属性)和#3(拼接)是最快的(不计算不改变原始数组的方法#1)。


这一直是一个热门话题,并引起了很多争议。实际上有很多正确的答案,并且因为这个答案已经被标记为已接受的答案很长时间了,所以我将在此处包含所有方法。

> 0恕我直言,更具可读性。并且两者之间没有性能差异。
2021-03-10 00:26:20
如果while(A.pop())数组中的项目为 falsey,则不能使用例如,A = [2, 1, 0, -1, -2] 将导致 A 等于 [2, 1]。甚至while(A.pop() !== undefined)不起作用,因为您可以将未定义的数组作为值之一。可能是编译器没有优化它的原因。
2021-03-14 00:26:20
while (A.length) { A.pop(); },不需要 > 0
2021-03-24 00:26:20
@DiegoJancic 方法 #1 不算数,因为它不清除数组。它创造了一个新的。它不应包含在基准测试中。
2021-03-30 00:26:20
@daghan,你想说什么根本不清楚。b即使在a分配了一个新数组之后,仍然保留对旧数组的引用cd继续引用同一个数组。因此,产出的差异是意料之中的。
2021-04-07 00:26:20

如果您需要保留原始数组,因为您有其他对它的引用也应该更新,您可以通过将其长度设置为零来清除它,而无需创建新数组:

A.length = 0;
@jollarvia ECMAScript 规范要求删除新长度以上的元素,因此任何正确的实现都会使任何无法访问的元素成为垃圾收集器。这并不一定意味着他们会立即缩小实际阵列的存储空间。具体来说,V8 仅在新长度小于原始长度的一半时才重新分配数组,但将长度设置为零实质上会在幕后重新分配新数组。
2021-03-15 00:26:20
@LosManos 即使在严格模式下,length也是一个特殊属性,但不是只读的,所以它仍然可以工作。
2021-03-16 00:26:20
@MattewCrumley 我做了一些测试,似乎 a.length = 0 不能有效清除整个数组。jsperf.com/length-equal-0-or-new-array我认为如果您有一个参考(并且您还没有添加要保留的额外属性),最好创建新数组,并保留旧的垃圾收集器,它将在适当的时候运行。
2021-03-16 00:26:20
ECMAScript 5 标准对此有何评论?
2021-03-24 00:26:20
@Pacerier:它仍然适用于 ES5。来自第 15.4 节:“...每当更改长度属性时,名称为数组索引且值不小于新长度的每个属性都会自动删除”
2021-04-04 00:26:20

这里最快的落实工作,同时保持相同的阵列(“可变”):

function clearArray(array) {
  while (array.length) {
    array.pop();
  }
}

仅供参考,它不能简化为while (array.pop()):测试将失败。

仅供参考MapSet定义clear()clear()对于Array来说似乎也是合乎逻辑的

typescript版本:

function clearArray<T>(array: T[]) {
  while (array.length) {
    array.pop();
  }
}

相应的测试:

describe('clearArray()', () => {
  test('clear regular array', () => {
    const array = [1, 2, 3, 4, 5];
    clearArray(array);
    expect(array.length).toEqual(0);
    expect(array[0]).toEqual(undefined);
    expect(array[4]).toEqual(undefined);
  });

  test('clear array that contains undefined and null', () => {
    const array = [1, undefined, 3, null, 5];
    clearArray(array);
    expect(array.length).toEqual(0);
    expect(array[0]).toEqual(undefined);
    expect(array[4]).toEqual(undefined);
  });
});

这里更新了 jsPerf:http : //jsperf.com/array-destroy/32 http://jsperf.com/array-destroy/152

jsPerf 离线。类似基准:https : //jsben.ch/hyj65

@thefourtheye 不修改全局范围的重点是因为您不知道其他人的代码是否已经(或将要)使用该名称。我建议在本地范围内使用一个函数。因此,在您的应用程序/库的IIFE 中,执行function clear(arr) { while(arr.length) arr.pop(); },然后使用clear(arr)而不是清除数组arr.clear()
2021-03-19 00:26:20
@thefourtheye 很好的性能解决方案,尽管我同意@naomik,但您不应修改本机对象。说它应该存在是无关紧要的,问题是您正在修改globals,这很糟糕。如果您将代码提供给其他人使用,那么它应该没有不可预见的副作用。想象一下,如果另一个库修改了Array.prototype并且它做了一些稍微不同的事情,那么您的整个代码都有[].clear()轻微的错误。调试起来不会很有趣。所以,一般信息是:不要修改全局变量。
2021-03-26 00:26:20
@naomik 但这是基本功能之一,默认情况下应该存在。
2021-03-31 00:26:20
事实证明,这种方法比.splice()慢得多.length=0基准不正确。请参阅我更新的答案。
2021-04-04 00:26:20
TT 您的答案是唯一正确且快速(同时)但“赞成票”少得多的答案。好吧,似乎人们喜欢缓慢的漂亮解决方案:/
2021-04-09 00:26:20

一个更跨浏览器友好和更优化的解决方案是使用如下splice方法清空数组 A 的内容:

A.splice(0, A.length);

@alex 不,它不会splice修改数组并返回已删除的条目。首先阅读文档:developer.mozilla.org/en-US/docs/JavaScript/Reference/...
2021-03-17 00:26:20
为什么这更跨浏览器友好?哪些浏览器对 A.length 有问题?
2021-03-20 00:26:20
我也发现这A.splice(0)也有效。
2021-03-21 00:26:20
@jm2 你所说的并不完全正确。它实际上修改了有问题的数组,随后所有引用都会受到影响。在我的 jsFiddle 上查看测试:jsfiddle.net/shamasis/dG4PH
2021-03-31 00:26:20
我们可以通过使用逗号运算符:来防止返回结果数组A.splice(0, A.length),0;这将留下一个返回值0一样A.length = 0;会。结果数组仍然被创建,应该会导致脚本运行得更慢:(jsperf ~56% 慢)。浏览器实现会影响这一点,尽管我认为没有理由splice比设置length.
2021-04-07 00:26:20

到目前为止,获得不少于 2739 票的答案具有误导性和不正确性。

问题是:“如何清空现有数组?” 例如对于A = [1,2,3,4]

  1. 说“A = []就是答案”是无知且绝对错误的。[] == []假的

    这是因为这两个阵列是两个独立的个体对象,具有自己的两个身份,在数字世界中占据了自己的空间,各自独立。


假设您的母亲要您清空垃圾桶。

  • 你不会带来一个新的,就好像你已经完成了你被要求的事情。
  • 相反,您清空垃圾桶。
  • 您不会用新的空罐替换装满的罐子,也不会从装满的罐子上取下标签“A”并将其贴在新罐上,如下所示 A = [1,2,3,4]; A = [];

清空数组对象是有史以来最简单的事情:

A.length = 0;

这样一来,“A”下的罐子不仅是空的,而且干净如新!


  1. 此外,在罐子变空之前,您不需要手动清除垃圾!你被要求一回合彻底清空现有的垃圾桶,在罐子变空之前不要捡垃圾,如下所示:

    while(A.length > 0) {
        A.pop();
    }
    
  2. 也不是,将左手放在垃圾箱底部,用右手握住垃圾箱的顶部,以便能够将其内容拉出,如下所示:

    A.splice(0, A.length);
    

不,你被要求清空它:

A.length = 0;

这是唯一正确清空给定 JavaScript 数组内容的代码。

因此,我宁愿自己清除它。一个清晰的方法可以被原型化,但这只是丑陋的。我的观点是,这个实现应该已经存在,这样 10 000 多名开发人员就不必花费数小时阅读这个线程,而不考虑所有其他花费更多时间进行基准测试的人。
2021-03-16 00:26:20
您建议的解决方案的唯一问题是垃圾仍然存在,只是您更改了告示板说没有垃圾。对旧数组的引用应该仍然存在。你能确定垃圾收集器在设置 .length = 0 时也会删除对数组及其属性的所有引用吗?我认为它确实如此,但对我来说这很神奇。.clear() 方法至少可以避免混淆。
2021-03-20 00:26:20
因为要完成它应该做的事情,必须删除所有引用。.length = 0 甚至不是方法调用,因此如果在将其设置为 0 时采取了其他操作(在大多数浏览器中通过定义 setter 进行),我仍然认为它太神奇了,无法真正相信它会做它应该做的去做。
2021-03-21 00:26:20
我从来没有说过这个解决方案是错误的。问题是这整个线程是完全不必要的。超过 3000 票表明,试图找出最好的方法应该使 EMCA 破解头开发人员添加这种方法成为一个足够有效的案例。没有人应该去弄清楚它。有三到四种不同的方法来做到这一点。在某些基准测试中,长度解决方案比其他解决方案慢得多。此外,将 .length = 0 设置为任何合理的开发人员的想法都不会令人满意。
2021-03-26 00:26:20
我喜欢这个答案中与现实世界的隐喻。感人的!
2021-03-29 00:26:20