有没有一种方法可以清空一个数组,如果可能的话,还可以使用.remove()?
例如,
我该怎么倒?
- 这里有一个具有不同可能性的基准:jsben.ch//7qyi1
清除现有数组A的方法:
方法1
(这是我对这个问题的原始答案)
此代码将把变量A设置为新的空数组。如果您没有在任何其他地方引用原始数组A,这是完美的,因为这实际上创建了一个全新的(空)数组。您应该小心使用此方法,因为如果您从另一个变量或属性引用了此数组,原始数组将保持不变。仅当您仅通过数组的原始变量A引用数组时才使用此选项。
这也是最快的解决方案。
此代码示例显示使用此方法时可能遇到的问题:
1 2 3 4
| 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(如Matthew Crumley建议)
这将通过将现有数组的长度设置为0来清除该数组。一些人认为这可能不适用于所有的JavaScript实现,但事实证明并非如此。它在ECMAScript 5中使用"严格模式"时也可以工作,因为数组的长度属性是读/写属性。
方法3(安东尼建议)
使用.splice()将很好地工作,但是由于.splice()函数将返回一个包含所有已删除项的数组,因此它实际上将返回原始数组的副本。基准测试表明,这对业绩没有任何影响。
方法4(根据Tanguy_k的建议)
1 2 3
| while(A.length > 0) {
A.pop();
} |
这个解决方案不是很简洁,也是最慢的解决方案,与最初答案中引用的早期基准相反。
性能
在清除现有数组的所有方法中,方法2和3的性能非常相似,并且比方法4快得多。看看这个基准。
正如Diadistis在下面的答案中指出的,用于确定上述四种方法性能的原始基准存在缺陷。原始基准重新使用已清除的数组,因此第二次迭代正在清除已为空的数组。
以下基准修复了此缺陷:http://jsben.ch//hyj65。它清楚地表明,方法2(长度属性)和3(拼接)是最快的(而不是不改变原始数组的计数方法1)。
这一直是一个热门话题,引起了很多争议。实际上有很多正确的答案,因为这个答案已经被标记为公认的答案很长一段时间了,我将在这里包括所有的方法。如果你对这个答案投赞成票,请把我提到的其他答案也投反对票。
- while (A.length) { A.pop(); },不需要> 0。
- > 0的可读性更强。两者之间没有性能差异。
- var a=[1,2,3];var b=a;a=[];console.log(b.length);var c=[1,2,3];var d=c;while(c.length)c.pop();console.log(d.length);
- @大汉,你想说什么一点也不清楚。即使在a被分配了一个新的数组之后,b仍然保留对旧数组的引用。c和d继续引用同一数组。因此,预期产出差异。
- 我为每个方法添加了基准,jspef.com/empty-javascript-array。将长度设置为0几乎总是最慢的方法,尽管它是最可读的方法,因此我建议使用它。
- 您所说的"在某些(大多数)中返回原始数组的副本"是什么意思?javascript实现。"?在所有的实现中不应该都是这样吗?
- @我觉得你是对的。我会改正的。另一方面,一个非常聪明的JavaScript实现可能会决定内联函数并对其进行优化,如果不使用返回值,则不会返回原始数组。
- 有没有人费心去弄清楚为什么这种完全非传统的"同时/流行"的东西在实践中似乎是最快的?
- 仅供参考,方法4在Chrome中是最快的,即在FF和Safari中,第一种方法是目前为止的胜利。方法2一直是最慢的。
- @diegojancic方法1不算数,因为它不清除数组。它创造了一个新的。它不应该包含在基准中。
- 当(a.pop())也工作时
- @是的,但比while(A.length > 0) A.pop();慢5倍。见jspef.com/array-destroy/138
- @Philippleybaer很有趣,我想知道为什么编译器不优化这个
- 我编写了基准代码,并在Intel(R)Xeon(R)CPU [email protected]和16GB RAM上运行它。使用X64 V8 3.26版本构建,两个版本都有相同的性能,但是使用node运行代码时,我能够在(a.length>0)a.pop()明显更好的情况下重新生成代码。
- 但是,我没有在V8上启用曲轴
- 如果数组中的某个项是假的,则不能使用while(A.pop())。例如,a=[2,1,0,-1,-2]将导致等于[2,1]。即使是while(A.pop() !== undefined)也不能工作,因为您可以将一个未定义的数组作为其中一个值。可能是为什么编译器没有优化它。
- 请在您的帖子中包含我的答案,这样每个人都可以看到这些方法之间的实际性能差异。
- 如果数组是只读的,则a.length=0也适用于:a:值:[]
- 任何循环都会花费你O(n)
- @伊凡·布莱克,这是一个微不足道的变化。如果你打算这样做,那么你也可以更进一步,去掉大括号:while (A.length) A.pop();,在任何情况下,这不是一个非常有效的解决方案。
- 章鱼,大括号是可读性的基础。除此之外,A.length > 0在语义上更正确(然后A.length):77对134。
- a.length=0;不适用于typescript。为此,坚持A.接头(0,A.长度);
- @Ryanloggerythm对于普通数组,length属性在typescript中不是只读的,将其设置为0会很好地工作。
- 关于方法3:"a.splice(0,a.length)"是否确实需要第二个参数?"a.splice(0)"是否工作相同?
- 我还发现将variable with array设置为null,然后像这样分配新的数组非常有用:var arr = [a,b,c,d]; arr=null; arr=[]对于我来说,因为这个方法强制gc从删除的数组中删除所有引用的数据存储(如果您没有任何其他对该数据的引用,则为ofc)。
- 我希望我们能有.clear()方法,不是吗?.length=0;的问题在于,没有一种好的方法可以知道垃圾收集器将如何对此作出反应。数组应该仍然保留对其他实例的引用,尽管可能已经实现了一些魔法来管理这些实例。
- @Philippeleybaert又错了"它在ECMAScript 5中使用"严格模式"时也会起作用,因为数组的长度属性是读/写属性。"数组的长度"是一种扩展和修剪的完整方法。数组就像一列火车,其按索引排序的成员就像拖拽火车头的车厢。因此,通过简单地在指定的索引处分离,以相同的方式丢弃。我真的很想知道你从哪里知道ES5 Strict不起作用?!
- @Bekimbacaj你总是这么敌对吗?我添加了关于ecmascript 5的评论,因为有人声称在ecmascript 5中使用严格模式时设置长度不起作用。
- 显然,拼接(a)也可以。
- @milos no it no t.splice()不是全局函数。
- @Philippeleybaert,从什么时候开始指出你的错误和错误信息被视为敌意-我认为这是礼貌和友好的,足以指出有效的信息,从中你将能够学习和更好地理解。您的意思是,A = [ ]是一种清除已存在数组内容的方法,这是绝对不正确的。这是将新的空数组文字赋给现有变量名。现在这是敌对的,因为它会伤害你,并可能导致意想不到的错误。
- @philippeleybaert jfiddle.net/j7spcsqf
- @milos splice()是在jsfidle使用的库中定义的全局函数。它不是JavaScript的一部分。在jsbin中尝试同样的方法,你会发现它不起作用:splice is not defined。
- @Philippeleybaert我用方法2清除了一个数组,然后遇到了一个奇怪的错误。而方法1在相同的用例中工作得很好。这就是我在使用方法2:pbs.twimg.com/media/c l numaas6at.jpg:large时(在Google Chrome中)得到的结果。
- A=[1,2,3];B=A;两者都将打印原始数组。A=[];这将清除A而不是B。A=[1,2,3];B=A;A.length=0;这将清除A和B。
- 据我所知,我们可以使用方法2(a.length=0),因为它既快又容易写
- 当我有对象数组时,将长度设置为0不起作用
- @菲利浦也许更易读些。也许对javascript的真实性概念不太熟悉。
- 方法1不清除a所指向的数组,因此它是错误的答案。
- @马兹,这对我来说似乎不正确,尽管我可能误解了你。当我创建一个对象数组时,例如const ary = [{a:1},{a:2}];,那么我可以通过将长度设置为0来清除它,即ary.length = 0;。
- @Philippeleybaert,也许您可以在回答中包括以下内容(根据您的选择):截至ES6/2015,如果A与let或var声明,或未声明,即let A=[3,4]、var A=[3,4]或A=[3,4]声明,所有4种方法都将有效。但是,方法1无法处理声明为常量的变量。例如,const A = [3,4]; A = [];将产生TypeError: Assignment to constant variable,而const A = [3,4]; A.length = 0;等(即方法2、3和4)将起作用。
- 我来自嵌入式世界,我找不到比A = []更好的A.length = 0方法。就过程性能而言,我理解,但是记忆呢?垃圾收集器如何处理这些不同的方法?对于很多重数组,方法2和3是否仍然更好?
- 上面的方法1和2不应该用于客户端视图模型,如Vuejs和Knockout。它会破坏它们,它们不会检测到数组中的更改。
- 方法1在视图模型中工作得很好。
- 不知羞耻的人,你给这件小事投了多少票。也要尊重其他编程语言。
- @用户30478这是您对stackoverflow的贡献吗?你知道,这不是Reddit。
- A.length=0在ECMAScript 6中工作正常,无需严格……:d
- 对于不信以东的人1〔0〕,去主治台:以东1〔1〕。
- @卡尔斯泰芬,我不明白你觉得奇怪的是什么?创建一个包含四个项的数组,并将其分配给变量A和B。然后用A.length = 0清空(共享)数组,然后用B.length = 4将(仍然共享)数组的长度设置为4。结果是一个长度为4的数组,只包含未定义的项(或者不包含任何项,具体取决于您如何查看)。它仍然是一个单数组,由两个变量A和B引用。但是阵列被第一个A.length = 0按预期清空。
- @你说的正是发生的事情,我们都同意。我的评论是针对那些实际上还不相信大多数(如果不是所有的)现代浏览器已经设法使a.length=0成为清空数组的最有效方法:快速、干净、无内存泄漏、无新数组,即使您有其他变量引用它也能正常工作!VoRE和224!
- 如果数组是常量,删除所有项的最简单方法是:const { items } = this.props; items.splice(0, items.length);。
如果需要保留原始数组,因为对它的其他引用也应更新,则可以通过将其长度设置为零来清除它,而不创建新数组:
- 这是否适用于所有浏览器?
- @是的,它可以在所有浏览器中使用。
- ECMAScript 5标准对此有何说明?
- @Pacrier:它仍然在ES5中工作。从第15.4节:"…每当length属性发生更改时,其名称是值不小于新长度的数组索引的每个属性都会自动删除。"
- @Einar:javascript数组总是根据您放入的内容进行扩展,所以当您调用myarray.push(whatever)时,它会增加一个长度。因此,设置长度会截断数组,但它不是永久的。
- 此解决方案会导致/使内存泄漏成为可能吗?很明显,这取决于JS解释器,但它似乎有可能导致泄漏…
- @史蒂文西伯特,它不应该出现在一个正确实现的解释器中,我不知道有什么实现可以做到。当然,这是可能的,但它不可能比其他不正确的泄漏源更容易发生。
- 如果你使用"严格使用";它将不起作用。不允许设置只读参数。stackoverflow.com/questions/1335851/…
- @Lossmanos即使在严格模式下,length也是一个特殊属性,但不是只读的,所以它仍然可以工作。
- @MatthewCrumley我在Win8的IE10桌面模式下尝试过-它不起作用。不记得邮件的确切措辞-可能是我最初评论的措辞。
- @洛斯马诺斯,我觉得不对劲。您确定它是一个数组,而不是节点列表或其他类似数组的对象吗?我认为在这种情况下,length属性是只读的。
- @作为一个认真的开发人员,我不确定如果不能复制它,甚至不能在那时…
- 在for循环中动态创建元素时不要使用这种方法(这是我的情况)。改为使用Philippeleybaert Post。
- @Vken是指自动修正长度吗?
- @Vken谢谢你的参考。那么,谁将删除数组元素?垃圾收集器?
- 记住,如果您创建一个新的数组,GC稍后也会处理旧的数组!所以我们可以说arr.length = 0;=gc立即,arr = [];=gc以后
- "如果您需要保留原始数组,因为对它的其他引用也应该更新,"如果我没有任何其他引用,它仍然是最佳方法吗?
- @MattewCrumley我做了一些测试,似乎a.length=0不能有效地清除整个数组。jspef.com/length-equal-0-or-new-array我认为如果您有一个引用(并且没有添加您想要保留的额外属性),那么最好创建新的数组,并将旧的留给垃圾收集器,在适当的时候运行它。
- @不是唯一的办法。splice()和pop()方法也不会使其他引用无效。
- @Philippeleybaert为真,通过调用那些引用,您不会使引用无效。我仍然喜欢长度=0,与参考拼接相反(0,参考长度)
- 我们确定将长度设置为0的方法可以消除对不需要的数组元素的引用吗?直观地说,在我看来,这些引用仍然在数组对象的某个地方。它们可能会被其他数组元素覆盖,但似乎将其设置为0永远不会真正允许GC收集其余的内容,并且不需要的内存被除原始数组之外的所有内容阻止使用。也许他们为这个问题内置了一些逻辑?我想找个人解释一下。
- @ecmascript规范要求删除超过新长度的元素,因此任何正确的实现都将使任何不可访问的元素成为垃圾回收。这并不意味着它们会立即缩小实际阵列的存储空间。具体来说,V8仅在新长度小于原始长度的一半时重新分配数组,但将长度设置为零实际上是在后台重新分配新数组。
- 是的,垃圾收集问题正是我来这里的原因。对于我来说,无法通过将该值设置为零来了解执行哪种魔力和特殊逻辑,尤其是当它甚至不是方法调用时。我不知道实现人员实际上在处理什么,这太神奇了。我会跳出来的,我觉得速度会更快。可能比popping设置为undefined更快,所以不需要将任何内容加载到内存中(返回值)。这样我就控制住了。
- @从数组中弹出元素的momomo在内存方面可能具有相同的效果。规范中没有要求实现调整分配给数组的空间量的内容,但是据我所知,一旦长度低于某个阈值,它们都会减小大小。
- @momomo(续)如果您想保证数组在末尾尽可能紧凑,您需要创建一个新的数组并将旧的数组留作垃圾收集(假设您不共享该数组,在这种情况下这不是一个选项)。这是否有益取决于具体的用例。例如,如果您要再次填充数组,那么重用旧的分配空间将更有效,并降低GC压力。
- @Matthewcrumley你最后评论道,"旧的分配空间会更有效,减少GC压力。"-这就是我的观点,就是。length=0;你实际上没有释放内存。在我的用例中,我从头到尾迭代所有元素,它们是函数,一旦执行,它们就可以被删除。由于为每个迭代调整数组是昂贵的,特别是从乞讨到结束,我想在所有迭代结束时清除数组。我正在使用数组调用一个方法进行迭代,因此设置array=[]将不起作用。我需要清空数组。
- .length=0在我的例子中是有效的,但是我们回到您关于垃圾收集的评论。相反,我选择迭代来执行我的所有函数,然后再次迭代到pop-after。.length=0;如果我们有清晰的方法,这样人们就不必根据用例来处理所有类型的问题,那就更好了。这整条线和超过5000票的讨论证明了这一点:)
- 如何更新它,使所有引用的长度为0?
- @没电161这就是设定长度的方法。每个引用都指向内存中的同一个对象,因此在一个引用上设置长度将影响所有引用。
- 在ES6中,您希望使用const,而不是var,使新的init不那么有用。const arr.lenth = 0非常快。JSBEN CH/OZR0V
- 当我有对象数组时,将长度设置为0不起作用
- @马兹,我不知道你的意思。它不应该关心数组中的值类型。
- 谢谢你回来找我。我使用了typescript,同时我意识到我使用的数组有一个自定义类型,因此0-ing out the length属性不会删除数组的内容。我用了一个clear()方法。
这里是最快的工作实现while keeping the same array("mutable"):
1 2 3 4 5
| function clearArray(array) {
while (array.length) {
array.pop();
}
} |
仅供参考,它不能简化为while (array.pop()):测试将失败。
fyi map和set define clear(),将clear()用于数组似乎也是合乎逻辑的。
类型脚本版本:
1 2 3 4 5
| function clearArray<T>(array: T[]) {
while (array.length) {
array.pop();
}
} |
相应的测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| 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);
});
}); |
这里更新的jspef:http://jspef.com/array destroy/32http://jspef.com/array-destroy/152
- 你的答案是唯一正确和快速的(同时),但有一些更少的"赞成票"。嗯,人们似乎喜欢缓慢的漂亮解决方案:/
- @但这是一个基本功能,默认情况下应该存在。
- @这是一个很好的性能解决方案,虽然我同意@naomik,但您不应该修改本机对象。如果说应该有点离题了,问题是你在修改全局参数,这很糟糕。如果您提供的代码是供其他人使用的,那么它不应该有不可预见的副作用。想象一下,如果另一个库也修改了Array.prototype,并且它做了一些稍微不同的事情,那么整个代码[].clear()都有点错误。这对调试来说不是很有趣。所以,一般的信息是:不要修改全局变量。
- @杰皮洛拉,你有什么建议?是否可以添加,除非已经存在同名函数?
- @当然,不修改全局范围的关键是因为您不知道其他人的代码是否已经(或将要)使用该名称。我建议在本地范围内使用一个函数。因此,在应用程序/库的IIFE中,执行function clear(arr) { while(arr.length) arr.pop(); },然后用clear(arr)而不是arr.clear()清除数组。
- 内存使用情况如何?我看到幕后的length=0正在删除数组中的所有元素。在这种情况下,速度是否会带来更大的内存成本?10倍
- 我想说,为默认对象创建新的方法是非常好的,只要它有一些独特的名称。例如,我这样做是在它前面加上我的昵称,而这并不局限于这个例子。
- 这个基准在每个测试中移动数组填充。如果使用.pop()快速清除阵列会减慢下一个阵列的创建,那么这可能不是一个整体优化。
- 结果表明,该方法比.splice()和.length=0慢得多。基准不正确。查看我更新的答案。
- @Philippeleybaert我们还应该检查每次测试前后占用的内存。还要检查数组是否真的是空的。总之,array.length=0似乎是最佳路径。
一个更为跨浏览器友好和最佳的解决方案是使用splice方法清空数组A的内容,如下所示:
A.splice(0, A.length);
- 为什么这种跨浏览器友好?什么浏览器对a.length有问题?
- 如@alex所说,splice返回一个新数组。这不是你想在一个REPL中做的事情。你可以一直用void这个表达,但这不是一个优雅的解决方案。
- 这是最正确的答案,因为它实际上"清除数组内容并保留对原始数组对象的引用"。
- @JM2你所说的并不完全正确。它实际上修改了有问题的数组,随后所有引用都会受到影响。请参阅我的jsFiddle上的测试:jsFiddle.net/shamasis/dg4ph
- @alex no it not,splice修改数组并返回删除的条目。首先阅读文档:developer.mozilla.org/en-us/docs/javascript/reference/&hellip;
- @大卫不知道我为什么写这个。我一定是错过了p,把它和slice()混淆了。
- 我们可以使用逗号操作符:A.splice(0, A.length),0;来防止返回结果数组。这将留下与A.length = 0;相同的0的回报值。结果数组仍然被创建,应该会导致脚本运行速度变慢:(jspef大约慢56%)。浏览器的实现会影响这一点,尽管我看不出为什么splice比设置length更快。
- 与其他方法相比,splice速度也非常慢jspef.com/array-splice-vs-array-length-0/2
- 我还发现,刚才的A.splice(0)也有效。
- @科温。琥珀不错!A.6种方法中的第3种是拼接(0)!参见jsben.ch//vtds2(源于jsben.ch//hyj65-这里是"new init"的head-to-head:jsben.ch//3do76)
到目前为止,获得不少于2739张赞成票的答案是误导性的和不正确的。
问题是:"如何清空现有数组?"例如,对于A = [1,2,3,4]。
说"江户一〔5〕是答案"是无知和绝对错误的。[] == []是假的。
这是因为这两个阵列是两个独立的独立对象,具有各自的两个身份,在数字世界中占据各自的空间,各自独立。
比如说,你妈妈让你把垃圾桶倒空。
- 你不会像按要求做的那样带来新的。
- 相反,你倒空垃圾桶。
- 你不能用一个新的空罐替换装满的罐,也不能从装满的罐上取下标签"A"并把它贴在新的罐上,如A = [1,2,3,4]; A = [];所示。
清空数组对象是最简单的事情:
这样一来,"A"下的罐子不仅是空的,而且像新的一样干净!
此外,在垃圾桶清空之前,您不需要手动清除垃圾!你被要求一次性清空现有的垃圾桶,直到垃圾桶清空,如:
1 2 3
| while(a.length > 0) {
a.pop();
} |
也不要把你的左手放在垃圾桶的底部,右手放在垃圾桶的顶部,这样你就可以把垃圾桶里的东西拿出来,就像:
不,你被要求清空它:
这是唯一正确清空给定javascript数组内容的代码。
- 您建议的解决方案的唯一问题是垃圾仍然存在,只是您更改了通知板,说没有垃圾。对旧数组的引用应该仍然存在。当设置.length=0时,您确定垃圾收集器也将删除对数组及其属性的所有引用吗?我想是的,但对我来说那是魔法。一个.clear()方法至少可以避免混淆。
- 没有太阳,这根本不是真的。您可能希望测试并深入了解它们,然后再尝试将其作为这一核心JavaScript功能基础的坚实的东西加以反对。它不是"我的解决方案",而是基本的JS语法。虽然它可能是A.length = 0;,但它是清空数组的标准语法。如果您希望有一个方法,如A.clear,可以使用此标准语法轻松地将该方法添加到数组中:Array.prototype.clear = function(){this.length = 0}。玩得高兴。
- 我从未说过这个解决方案是错误的。问题是整个线程是完全不可靠的。超过3000张选票表明,试图找出最好的方法应该使它成为EMCA Crack Head开发人员添加此类方法的足够有效的理由。任何人都不应该去搞清楚。有三种-四种不同的方法。在一些基准中,长度解决方案比其他的慢得多。此外,对于任何合理的显影剂来说,设置.length=0的想法都不是一个令人满意的想法。
- 因为要完成它应该做的,必须删除所有引用。.length=0甚至不是一个方法调用,所以如果在它设置为0时还采取了其他操作(在大多数浏览器中,通过define setter),我仍然认为它太神奇了,无法真正相信它会做它应该做的事情。
- 因此,我宁愿自己澄清。一个清晰的方法可以被原型化,但这很难看。我的观点是,这个实现应该已经存在了,这样超过10000个开发人员就不必花费数小时来阅读这个线程,也不必考虑其他花费更多时间进行基准测试的开发人员。
- 只有一种方法可以清空数组,用新的传入数据填充它,然后再次丢弃它。所有其他的要么不是,要么是可笑的低效和不可原谅的CPU消耗。唯一可行的选择是A(n) = A.splice( 0, A.length );,以防您需要备份以前的内容。P.S.Array.length是一种读写属性方法,以防您忽略了这一基本事实。也就是说,您可以将其扩展到一个新的长度,您不能将其修剪到您想要的任何长度,此外,您可以通过将其长度缩短为0来丢弃所有成员。这是一把瑞士刀。
- @Bekimbacaj,因为你的答案被否决了,这是迄今为止最好和最简单的解释,解释了为什么其他解决方案,而不是A.length = 0是不合适的。我希望我能投更多的票!!
- 我同意Ghego1的观点,其他的答案可能会更被否决,但这一个是迄今为止最好的,因为它解释了为什么和为什么。此外,测试(jsben.ch/rh0nb)表明,信任浏览器的内部垃圾收集总是更好的(连续运行时,拼接(0)、拼接(0,长度)和长度=0交替出现在第一位)。
- 我喜欢这个答案中与现实世界的隐喻。给人印象深刻!
性能测试:
http://jspef.com/array-clear-methods/3
1 2 3 4 5 6
| a = []; // 37% slower
a.length = 0; // 89% slower
a.splice(0, a.length) // 97% slower
while (a.length > 0) {
a.pop();
} // Fastest |
- 添加百分比更改在不注意平台的情况下没有多大用处。在我的机器上,Pop在Chrome34中的速度只是稍微快一点,但实际上比最新的Firefox中的[]慢。
- 在WindowsNT 6.3 64位的火狐39.0 32位测试中,A=[]速度最快!
- 当然,创建阵列的新实例比循环和弹出阵列要快…因此,如果在chrome中弹出速度更快,则意味着创建新的数组是错误的。
- 这个测试结果在铬下肯定有可疑之处。弹出式循环怎么能比其他3种解决方案更快呢?
- @不是的。这是最慢的方法。基准测试有缺陷。
- 请删除此答案,因为它是错误的,并链接到一个毫无意义的有缺陷的测试作为虚假证据。
- 显示一些基准以支持您的答案
- 这些年来,性能结果发生了很大的变化——令人惊讶的是,不同版本的Chrome看起来有多么的不同……"重新定义"是Chrome 68的明确性能赢家。(但仍然无法解决问题)
您可以将此添加到您的javascript文件中,以允许"清除"您的数组:
1 2 3
| Array.prototype.clear = function() {
this.splice(0, this.length);
}; |
然后你可以这样使用它:
1 2
| var list = [1, 2, 3];
list.clear(); |
或者,如果你想确定你没有销毁什么东西:
1 2 3 4 5
| if (!Array.prototype.clear) {
Array.prototype.clear = function() {
this.splice(0, this.length);
};
} |
很多人认为你不应该修改本地对象(比如数组),我倾向于同意。请谨慎决定如何处理。
- @娜奥米克,你能解释一下你为什么不愿意做这种事吗?
- 修改诸如数组和字符串之类的javascript原语函数是"令人不快的"。您可能正在重载一个已经存在的函数并废弃对象类。可能有一个模糊的javascript引擎已经有clear(),并期望它以不同的方式运行。我只说小心点。
- 如果在数组成员上执行foreach,会突然开始包含一个clear键,那么该怎么办?
- 作为参考:为什么扩展本机对象是一种坏做法?
在回答和评论中有很多关于while;pop/shift性能的混淆和错误信息。while/pop解决方案(如预期)的性能最差。实际上,对于在循环中运行代码段的每个示例,安装程序只运行一次。如:
1 2 3 4 5 6 7 8 9 10 11
| 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://jspef.com/empty-javascript-array-redux
警告:即使在这个版本的测试中,您也看不到真正的区别,因为克隆数组会占用大部分测试时间。它仍然表明,splice是清除阵列的最快方法(不考虑[],因为虽然它是最快的,但实际上并没有清除现有阵列)。
- 很有道理!我将用正确的基准结果更新原始答案。
- 我不敢相信没有人发现这个基准误差。有超过50万的浏览量,你会期望有人注意到。伟大的工作
1 2 3
| Array.prototype.clear = function() {
this.length = 0;
}; |
叫它:array.clear();。
- 请不要鼓励修改本机对象。
- 为什么人们会有这样的倾向:抓住公认的答案并将其放入原型函数中?你真的在你的项目中这样做吗?您是否有一个庞大的原型添加库,包括在每个项目中?
- 为什么不只键入array.length=0?
- 请黑客/开发者……不要修改东西,那会把我们带到哪里去。
- 这怎么能得到赞成票?据我所知,没有浏览器允许使用this = ..。编辑:我明白了,以前版本的答案是不同的。
- @defmx我的回答必须是一个很长的形式,可能已经有数百人说了。如果你好奇的话,可以在谷歌上搜索"javascript不要修改本机"或者其他东西。如果你还有问题,问一个新问题。
- @Naomik"请不要鼓励修改本地对象。"——我完全同意这一点,但仅仅重复这句话本身就会被认为是傲慢的。提出这样一个解决方案的人可能不知道后果,把这句话放在他们身上,而不是提供简短的解释或链接,并不能传达出"我们,比你聪明的人,告诉你不要这样做,因为我们知道得更好"。
- @约翰,我实际上有给出完全相反的建议的答案,但当然有附加的上下文。我有责任尽可能有效地沟通,但我也同意被误解。我不总是有时间为我说的每一句话提供引文和参考资料,这也没关系。有了这样的答案(除了一小段代码和零解释),我觉得有义务向另一个方向推进,让读者知道某个特定的答案是站不住脚的——即使这样的努力只是略大于答案。
- 作为参考:为什么扩展本机对象是一种坏做法?
- 我不同意。向本机对象添加原型是一种糟糕的做法。查看@emilebergeron link了解原因。
如果您对内存分配感兴趣,可以将每个方法与chrome dev工具的时间线选项卡结合使用类似于此jfiddle的工具进行比较。您将希望在"清除"数组后使用底部的垃圾箱图标强制垃圾收集。这将为您选择的浏览器提供更明确的答案。这里的很多答案都是老生常谈的,我不会依赖它们,而是像上面的@tanguy_k's answer中的测试。
(有关上述选项卡的介绍,您可以在此处查看)
StackOverflow强制我复制jsFiddle,所以这里是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| <html>
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
}
<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管理字符串的方式与其他基元类型不同,更不用说对象数组。类型可能会影响发生的情况。
A.splice(0);
我只是在我正在处理的代码上做了这个。它清除了阵列。
- 不,您刚刚用一个新创建的匿名数组容器交换了一个命名数组容器。` var a=[1,2,3,4];var b;b=a.splice(0);console.log(a);console.log(b);'
如果您正在使用
然后将新的数组引用分配给,如果在中的引用已经分配给任何其他变量,则它也不会清空该数组,因此垃圾收集器不会收集该内存。
为Ex.
1 2 3 4
| var a=[1,2,3];
var b=a;
a=[];
console.log(b);// It will print [1,2,3]; |
或
当我们指定a.length时,我们只是重置数组的边界,其余数组元素的内存将由垃圾收集器连接。
而不是这两个解决方案更好。
和
1 2 3
| while(a.length > 0) {
a.pop();
} |
根据kenshou.html之前的答案,第二种方法更快。
- 除了在EDOCX1上出错(0),我不明白这个新的答案会给线程增加什么?
- @我只想关注数组的实际内存表示
- 当执行a.length=0;时,您是否有任何源来确认哪些JS引擎将创建新的数组?这些引擎对a.length=500;和a.length=4;有什么作用?
- 我在大多数浏览器上都尝试过,比如IE、火狐、Chrome,它正在创建新的数组。如果您将长度设置为大于0,那么它将创建一个包含未定义元素的数组,也就是说,它将只保存一些内存位置。
- var a = [1]; var b = a; a.length = 0; console.log(b)打印Array [ ],所以它看起来不像是在创建一个新的数组。
您可以很容易地创建一个函数来实现这一点,更改长度,甚至将其作为remove()函数添加到本机数组中以供重用。
假设您有这个数组:
1
| var arr = [1, 2, 3, 4, 5]; //the array |
好的,只需运行以下命令:
1
| arr.length = 0; //change the length |
结果是:
清空数组的简单方法…
也可以使用循环,这不是必需的,但只是另一种方法:
1 2 3 4 5 6 7 8
| /* could be arr.pop() or arr.splice(0)
don't need to return as main array get changed */
function remove(arr) {
while(arr.length) {
arr.shift();
}
} |
还有一些棘手的方法可以考虑,例如:
1
| arr.splice(0, arr.length); //[] |
因此,如果arr有5个项目,它将从0中拼接5个项目,这意味着数组中不会保留任何内容。
其他方法,例如简单地重新分配数组:
如果您查看数组函数,有许多其他方法可以做到这一点,但最推荐的方法是更改长度。
正如我在第一个地方所说,您还可以原型remove(),因为它是您问题的答案。您可以简单地选择上面的方法之一,并将其原型化为JavaScript中的数组对象,如下所示:
1 2 3
| Array.prototype.remove = Array.prototype.remove || function() {
this.splice(0, this.length);
}; |
您可以这样简单地调用它来清空JavaScript应用程序中的任何数组:
使用简的初始建议的修改版本:
1 2 3 4
| var originalLength = A.length;
for (var i = originalLength; i > 0; i--) {
A.pop();
} |
- 你为什么要做这种事?为什么还要添加两个变量和一堆代码来做同样的事情?
如果使用常量,则没有选择:
1
| const numbers = [1, 2, 3] |
您不能重新签名:
只能截断:
清空阵列的当前内存位置:'myArray.length = 0'或'myArray.pop() UN-till its length is 0'。
- length:可以随时设置长度属性来截断数组。通过更改数组的长度属性来扩展数组时,实际元素的数量会增加。
- pop():pop方法从数组中删除最后一个元素,并返回已删除的值。
- shift():shift方法删除零索引处的元素,并向下移动连续索引处的值,然后返回删除的值。
例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| var arr = ['77'];
arr.length = 20;
console.log("Increasing :", arr); // (20) ["77", empty × 19]
arr.length = 12;
console.log("Truncating :", arr); // (12) ["77", empty × 11]
var mainArr = new Array();
mainArr = ['1', '2', '3', '4'];
var refArr = mainArr;
console.log('Current', mainArr, 'Refered', refArr);
refArr.length = 3;
console.log('Length: ~ Current', mainArr, 'Refered', refArr);
mainArr.push('0');
console.log('Push to the End of Current Array Memory Location
~ Current', mainArr, 'Refered', refArr);
mainArr.poptill_length(0);
console.log('Empty Array
~ Current', mainArr, 'Refered', refArr);
Array.prototype.poptill_length = function (e) {
while (this.length) {
if( this.length == e ) break;
console.log('removed last element:', this.pop());
}
}; |
- "length:pops直到数组的长度达到指定的大小。"谁告诉过你这种胡说八道?
- @bekimbacaj在本质上,它也有同样的效果。它应该说是length = ?,而不仅仅是length。
- @Bekimbacaj我更新了我的答案,我只是假设长度会一直跳到长度,但现在我更正了长度只会截断或增加数组的大小。
我很惊讶还没有人提出这样的建议:
1 2 3
| let xs = [1,2,3,4];
for (let i in xs)
delete xs[i]; |
这将生成一个与其他解决方案处于完全不同状态的数组。在某种意义上,数组已"清空":
1 2 3 4 5 6 7 8 9 10 11
| xs
=> Array [ <4 empty slots> ]
[...xs]
=> Array [ undefined, undefined, undefined, undefined ]
xs.length
=> 4
xs[0]
=> ReferenceError: reference to undefined property xs[0] |
您可以使用[,,,,]或Array(4)生成等效数组。
- 对于另一个问题,这可能是一个很好的答案:"如何将数组中的所有元素转换为未定义的元素"。
如果需要清空Angular 2+Formarray,请在下面使用。
1 2 3 4 5
| public emptyFormArray(formArray:FormArray) {
for (let i = formArray.controls.length - 1; i >= 0; i--) {
formArray.removeAt(i);
}
} |
- 这是不相关的,甚至不是JavaScript。
- 为什么这个人会存在??