题 如何在JavaScript中清空数组?


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

例如,

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

我怎么能清空它?


2199
2017-08-05 09:08


起源


这里有一个不同可能性的基准: jsben.ch/#/7QyI1 - EscapeNetscape


答案:


清除现有阵列的方法 A

方法1

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

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

方法2 (如 建议 通过 马修克拉姆利

A.length = 0

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

方法3 (如 建议 通过 安东尼

A.splice(0,A.length)

运用 .splice() 将完美,但自从 .splice() 函数将返回一个包含所有已删除项的数组,它实际上将返回原始数组的副本。基准测试表明,这对绩效没有任何影响。

方法4 (如 建议 通过 tanguy_k

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

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

性能

在所有清算方法中 现有阵列方法2和方法3在性能上非常相似,并且比方法4快很多。见此 基准

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

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


这一直是一个热门话题和争议的原因。实际上有很多正确的答案,并且由于这个答案在很长一段时间内已被标记为已接受的答案,因此我将在此处包含所有方法。如果您投票赞成此答案,请同时提及我所引用的其他答案。


3457
2017-08-05 09:10



while (A.length) { A.pop(); },没必要 > 0 - Ivan Black
> 0 是更可读的恕我直言。并且两者之间没有性能差异。 - Philippe Leybaert
@daghan,你一点都不清楚。 b 即使之后仍然拥有对旧数组的引用 a 被分配一个新的。 c 和 d 继续引用相同的数组。因此预计产出的差异。 - shovavnik
@DiegoJancic方法#1不计算,因为它不清除数组。它创造了一个新的。它不应该包含在基准中。 - Philippe Leybaert
你不能用 while(A.pop()) 如果数组中的项是假的。例如,A = [2,1,0,-1,-2]将导致A等于[2,1]。甚至 while(A.pop() !== undefined) 不起作用,因为您可以将未定义的数组作为其中一个值。可能是为什么编译器没有优化它。 - Jonathan Gawrych


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

A.length = 0;

2253
2017-08-05 16:29



@Acorn是的,它适用于所有浏览器。 - Matthew Crumley
ECMAScript 5 Standard对此有何看法? - Pacerier
@Pacerier:它仍然适用于ES5。从第15.4节开始:“......每当更改length属性时,将自动删除名称为数组索引且其值不小于新长度的每个属性” - Matthew Crumley
@LosManos即使在严格模式下, length 是一个特殊的属性,但不是只读的,所以它仍然可以工作。 - Matthew Crumley
@MattewCrumley我做了一些测试,似乎a.length = 0不能有效清除整个数组。 jsperf.com/length-equal-0-or-new-array 我想如果你有一个refence(并且你没有添加你想要保留的额外属性),最好创建一个新的数组,并将旧的数据留给垃圾收集器,它将在适当的时候运行。 - Paul Brewczynski


这是最快的工作实施 而 保持相同的阵列 ( “可变”):

Array.prototype.clear = function() {
  while (this.length) {
    this.pop();
  }
};

FYI 地图 定义 clear() 所以这似乎合乎逻辑 clear() 对于 排列 太。

或者作为一个 Underscore.js mixin

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

或者一个简单的功能:

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

打字稿 版:

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

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

以及随之而来的测试:

describe('Array', () => {
  it('should clear the array', () => {
    let array = [1, 2, 3, 4, 5];
    array.clear();
    expect(array.length).toEqual(0);
    expect(array[0]).toEqual(undefined);
    expect(array[4]).toEqual(undefined);

    // Even with undefined or null inside
    array = [1, undefined, 3, null, 5];
    array.clear();
    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


256
2018-06-25 20:32



TT你的答案是唯一一个正确而快速(同时)但有一些更少“赞成”的答案。好吧,似乎人们喜欢漂亮的解决方案: - Ai_boy
@naomik但这是基本功能之一,默认应该存在。 - thefourtheye
@thefourtheye良好的性能解决方案,虽然我同意@naomik,但你不应该修改原生对象。说它应该存在,问题在于你正在修改 全局,这很糟糕。如果您提供其他人使用的代码,那么它应该没有不可预见的副作用。想象一下,如果另一个图书馆 也 修改了 Array.prototype 它正在做一些略有不同的事情,然后是整个代码 [].clear() 有点不对劲。这对调试来说并不好玩。所以,一般的信息是:不要修改全局变量。 - jpillora
@thefourtheye不修改全局范围的重点是因为 你不会知道的 如果其他人的代码已经(或将要)使用该名称。我建议在本地范围内使用一个函数。所以,在你的应用程序/库中 IIFE,做 function clear(arr) { while(arr.length) arr.pop(); },然后清除数组 clear(arr) 代替 arr.clear()。 - jpillora
事实证明这种方法比慢很多 .splice() 和 .length=0。基准测试不正确。看到我更新的答案。 - Philippe Leybaert


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

A.splice(0, A.length);


182
2017-11-15 09:49



为什么这个跨浏览器友好?什么浏览器有A.length的问题? - stricjux
@ jm2你所说的并不完全正确。它实际上修改了有问题的数组,随后所有引用都受到影响。看看我的jsFiddle上的测试: jsfiddle.net/shamasis/dG4PH - Shamasis Bhattacharya
@alex不,不, splice 修改数组并返回已删除的条目。首先阅读文档: developer.mozilla.org/en-US/docs/JavaScript/Reference/... - David
我们可以通过使用来防止返回结果数组 逗号运算符: A.splice(0, A.length),0;。这将留下返回值 0 就像 A.length = 0; 将。生成的数组仍然是创建的 应该 导致脚本运行速度变慢:(jsperf 慢约56%)。浏览器实现会影响这一点,虽然我没有理由 splice 会比设定更快 length。 - Evan Kennedy
我也发现了 A.splice(0) 也有效。 - corwin.amber


到目前为止2739投票的答案都是误导和错误的。

问题是:“你如何清空你现有的阵列?”例如。对于 A = [1,2,3,4]

  1. 说“A = [] 答案是“无知而且绝对不正确。 [] == [] 是

    这是因为这两个数组是两个独立的,单独的对象,具有自己的两个身份,在数字世界中占据了自己的空间,每个都独立存在。


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

  • 你没有带来一个新的,好像你已经完成了你所要求的。
  • 相反,你清空垃圾桶。
  • 你没有用新的空罐替换填充的罐子,并且你没有从填充的罐子中取出标签“A”并将其粘贴到新的罐子中,如同在 A = [1,2,3,4]; A = [];

清空数组对象是最简单的事情:

A.length = 0;

这样,“A”下的can不仅是空的,而且还像新的一样干净!


  1. 此外,在罐子空了之前,您不需要用手取出垃圾!您被要求在一个回合中完全清空现有的一个,而不是在罐子变空之前拿起垃圾,如:

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

    A.splice(0, A.length);
    

不,你被要求清空它:

A.length = 0;

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


61
2018-04-30 15:18



建议的解决方案唯一的问题是垃圾仍然存在,只是你改变了告示板,说没有垃圾。应该仍然存在对旧数组的引用。设置.length = 0时,你能确定垃圾收集器,还会删除对数组及其属性的所有引用吗?我认为确实如此,但对我来说这是神奇的。一个.clear()方法是可取的,以避免混淆至少说。 - momo
我从未说过这个解决方案是错误的。问题是这整个线程是完全不必要的。超过3000张投票显示,试图弄清楚最佳方法是什么应该使它成为EMCA破解头开发人员添加这种方法的有效案例。没有人应该通过搞清楚。有三种 - 四种不同的方法。在某些基准测试中,长度解决方案比其他测试慢得多。此外,对任何合理的开发者来说,设置.length = 0的想法都不会令人满意。 - momo
因为要完成它应该完成的任务,所以必须删除所有引用。 .length = 0甚至不是一个方法调用,所以如果在设置为0时有其他动作(在大多数浏览器中通过定义setter),我仍然会认为实际上相信它做了它想象的太神奇了去做。 - momo
因此,我宁愿自己清楚。一个明确的方法可以原型,但这只是丑陋。我的观点是,这个实现应该已经存在,以便超过1万名开发人员不必花费数小时阅读这个帖子,而不是考虑花费更多时间进行基准测试的所有其他人。 - momo
只有一种方法可以清空你的数组,用新传入的数据填充它并再次丢弃它。所有其他人要么没有,要么是非常低效和难以置信的cpu饥饿。唯一可行的替代方案是 A(n) = A.splice( 0, A.length ); 如果您需要备份以前的内容。附: Array.length 如果你错过了这个基本事实,它是一个读写属性\方法。意思是,你可以将它扩展到一个新的长度,你不能将它修剪到你想要的任何长度,其中你可以通过将其长度缩短为0来丢弃所有成员。它是阵列的瑞士刀。 - Bekim Bacaj


性能测试:

http://jsperf.com/array-clear-methods/3

a = []; // 37% slower
a.length = 0; // 89% slower
a.splice(0, a.length)  // 97% slower
while (a.length > 0) {
    a.pop();
} // Fastest

59
2018-05-14 07:14



在没有注意到您的平台的情况下添加百分比变化也没什么用处。在我的机器上,在Chrome 34中pop的速度非常快,但在最新的Firefox中实际上比[]慢。 - Matt Styles
在Windows NT 6.3 64位上的Firefox 39.0 32位测试中,a = []是最快的! - Reza-S4
在Chrome下的测试结果中肯定有些可疑。在其他3种解决方案中,爆破循环如何快得多? - chqrlie
@chqrlie不是。这是最慢的方法。基准测试存在缺陷。 - Philippe Leybaert
请删除这个答案,因为它是错误的,并链接到无意义的有缺陷的测试作为假证据。 - James Wakefield


您可以将其添加到JavaScript文件中以允许“清除”数组:

Array.prototype.clear = function() {
    this.splice(0, this.length);
};

然后你可以像这样使用它:

var list = [1, 2, 3];
list.clear();

或者如果你想确定你没有破坏某些东西:

if (!Array.prototype.clear) {
    Array.prototype.clear = function() {
       this.splice(0, this.length);
    };
}

很多人认为你不应该修改原生对象(比如Array),我倾向于同意。请谨慎决定如何处理此问题。


32
2017-12-11 02:58



@naomik你能解释一下为什么做这样的事情是不赞成的吗? - Undefined
修改javascript原始函数(如Array和String)是“不赞成的”。您可能会重载已存在的函数并删除对象类。可能有一个模糊的javascript引擎已经有clear()并期望它的行为方式不同。我说的就是小心谨慎。 - Design by Adrian
对数组成员进行foreach的问题将突然开始包括一个问题 clear 键? - ErikE
作为参考: 为什么扩展本机对象是一种不好的做法? - Emile Bergeron


Array.prototype.clear = function() {
    this.length = 0;
};

并称之为: array.clear();


16
2018-02-22 21:28



请不要鼓励修改本机对象。 - user633183
为什么人们会倾向于抓住已接受的答案并将其置于原型功能中?你真的在你的项目中这样做吗?您是否拥有包含在每个项目中的大量原型添加库? - nurettin
为什么不直接输入array.length = 0? - Design by Adrian
@naomik “请不要鼓励修改原生对象。”  - 我完全同意这一点,但只是重复这句话本身就是傲慢的。提出这样一个解决方案的人可能不会意识到后果,并且在他们上面放下这一行而不是提供简短的解释或链接并不能传达除了 “我们,比你聪明的人,告诉你不要这样做,因为我们知道的更好”。 - John Weisz
作为参考: 为什么扩展本机对象是一种不好的做法? - Emile Bergeron


关于while; pop / shift表现在答案和评论中存在很多混乱和错误信息。 while / pop解决方案(正如预期的那样) 表现最差。实际发生的情况是,对于在循环中运行代码段的每个样本,安装程序只运行一次。例如:

var arr = [];

for (var i = 0; i < 100; i++) { 
    arr.push(Math.random()); 
}

for (var j = 0; j < 1000; j++) {
    while (arr.length > 0) {
        arr.pop(); // this executes 100 times, not 100000
    }
}

我创建了一个正常工作的新测试:

http://jsperf.com/empty-javascript-array-redux

警告: 即使在这个版本的测试中,你实际上也看不到真正的区别,因为克隆数组会占用大部分测试时间。它仍然表明了这一点 splice 是清除阵列的最快方法(不采取 [] 考虑因为虽然它是最快的,但实际上并没有清除现有的数组。


15
2018-02-16 18:52



非常好点!我会用正确的基准测试结果更新原始答案。 - Philippe Leybaert
我无法相信没有人发现基准测试错误。有超过五十万次观看,你会发现有人会注意到它。伟大的工作Diadistis - Philippe Leybaert


如果您对内存分配感兴趣,可以使用类似的方法比较每种方法 这个jsfiddle 与chrome dev工具的时间线选项卡配合使用。您将需要使用底部的垃圾箱图标在“清除”阵列后强制进行垃圾回收。这应该为您选择的浏览器提供更明确的答案。这里的很多答案都很陈旧,我不会依赖它们,而是像@ tanguy_k上面的答案那样测试。

(有关上述标签的介绍,您可以查看 这里

Stackoverflow强迫我复制jsfiddle所以这里是:

<html>
<script>
var size = 1000*100
window.onload = function() {
  document.getElementById("quantifier").value = size
}

function scaffold()
{
  console.log("processing Scaffold...");
  a = new Array
}
function start()
{
  size = document.getElementById("quantifier").value
  console.log("Starting... quantifier is " + size);
  console.log("starting test")
  for (i=0; i<size; i++){
    a[i]="something"
  }
  console.log("done...")
}

function tearDown()
{
  console.log("processing teardown");
  a.length=0
}

</script>
<body>
    <span style="color:green;">Quantifier:</span>
    <input id="quantifier" style="color:green;" type="text"></input>
    <button onclick="scaffold()">Scaffold</button>
    <button onclick="start()">Start</button>
    <button onclick="tearDown()">Clean</button>
    <br/>
</body>
</html>

您应该注意它可能取决于数组元素的类型,因为javascript管理字符串的方式与其他基本类型不同,更不用说对象数组了。类型可能会影响发生的事情。


14
2017-12-11 23:19