在 JavaScript 中复制数组的最快方法 - 切片与“for”循环

IT技术 javascript arrays duplicates copy slice
2021-01-21 13:26:08

为了在 JavaScript 中复制数组:以下哪个使用起来更快?

Slice 方法

var dup_array = original_array.slice();

For 环形

for(var i = 0, len = original_array.length; i < len; ++i)
   dup_array[i] = original_array[i];

我知道这两种方法都只做一个浅拷贝:如果original_array包含对对象的引用,则不会克隆对象,但只会复制引用,因此两个数组都将引用相同的对象。但这不是这个问题的重点。

我只问速度。

6个回答

至少有6 (!) 种方法可以克隆数组:

  • 环形
  • Array.from()
  • 连接
  • 展开运算符(最快)
  • 地图 A.map(function(e){return e;});

有一个huuuge BENCHMARKS线程,提供以下信息:

  • 对于blink浏览器,slice()是最快的方法,concat()速度稍慢,while loop慢2.4 倍。

  • 对于其他浏览器while loop是最快的方法,因为这些浏览器没有针对slice和 的内部优化concat

2016 年 7 月仍然如此。

下面是简单的脚本,您可以将它们复制粘贴到浏览器的控制台中并运行几次以查看图片。他们输出毫秒,越低越好。

while 循环

n = 1000*1000;
start = + new Date();
a = Array(n); 
b = Array(n); 
i = a.length;
while(i--) b[i] = a[i];
console.log(new Date() - start);

n = 1000*1000;
start = + new Date();
a = Array(n); 
b = a.slice();
console.log(new Date() - start);

请注意,这些方法将克隆 Array 对象本身,但是数组内容是通过引用复制的,而不是深度克隆。

origAr == clonedArr //returns false
origAr[0] == clonedArr[0] //returns true
你错过了这个方法: A.map(function(e){return e;});
2021-03-15 13:26:08
遗憾的是,对于短数组,答案大不相同例如,在调用每个侦听器之前克隆一组侦听器。这些数组通常很小,通常是 1 个元素。
2021-03-21 13:26:08
@cept0 没有情绪,只是基准测试jsperf.com/new-array-vs-splice-vs-slice/31
2021-03-27 13:26:08
@Dan 那又怎样?您的测试用例结果:Firefox 30 nightly 仍然比 Chrome 快约 230%。检查 V8 的源代码,splice你会感到惊讶(同时...)
2021-04-02 13:26:08
您正在撰写有关闪烁浏览器的文章是不是blink只是一个布局引擎,主要影响HTML渲染,所以不重要?我想我们宁愿在这里谈论 V8、Spidermonkey 和朋友。只是让我困惑的一件事。启发我,如果我错了。
2021-04-06 13:26:08

从技术上讲slice 最快的方法。但是,如果添加0开始索引,速度会更快

myArray.slice(0);

myArray.slice();

https://web.archive.org/web/20170824010701/https://jsperf.com/cloning-arrays/3

链接已死。
2021-03-14 13:26:08
jsben.ch/56xWo - 有时slice()会更快,有时会更快slice(0)(在 Firefox 56 和基于 Chrome 的最新 Vivaldi 中)。slice(0, length)总是明显变慢(除了它在 Firefox 87 中是最快的)。
2021-03-14 13:26:08
这是不正确的,至少在我的机器上并且根据您自己的基准测试。
2021-03-16 13:26:08
@jave.web 你刚刚删除了数组的最后一个元素。完整副本是 array.slice(0) 或 array.slice(0, array.length)
2021-03-22 13:26:08
并且myArray.slice(0,myArray.length-1);myArray.slice(0);?
2021-03-30 13:26:08

es6方式怎么样?

arr2 = [...arr1];
@SterlingArcherarr2 = [].conact(arr1)arr2 = [...arr1]. [...arr1]语法将洞转换为undefined. 例如,arr1 = Array(1); arr2 = [...arr1]; arr3 = [].concat(arr1); 0 in arr2 !== 0 in arr3
2021-03-12 13:26:08
如果用 babel 转换: [].concat(_slice.call(arguments))
2021-03-21 13:26:08
不确定arguments来自哪里......我认为你的 babel 输出混合了一些不同的功能。更有可能是arr2 = [].concat(arr1)
2021-03-24 13:26:08
我在我的浏览器(Chrome 59.0.3071.115)中针对上面 Dan 的回答测试了这个。它比 .slice() 慢 10 倍以上。n = 1000*1000; start = + new Date(); a = Array(n); b = [...a]; console.log(new Date() - start); // 168
2021-03-25 13:26:08
仍然不会克隆这样的东西:[{a: 'a', b: {c: 'c'}}]. 如果c在“重复”数组中更改了 的值,它将在原始数组中更改,因为它只是引用副本,而不是克隆。
2021-04-05 13:26:08

深度克隆数组或对象的最简单方法:

var dup_array = JSON.parse(JSON.stringify(original_array))
它使用基元深度复制数组,其中属性是具有进一步基元/数组的数组。为此,没关系。
2021-03-10 13:26:08
初学者的重要提示:因为这取决于 JSON,所以这也继承了它的局限性。除其他外,这意味着您的数组不能包含undefined或任何functions。null在此JSON.stringify过程中,这两者都会为您转换其他策略,例如(['cool','array']).slice()不会更改它们,但也不会对数组内的对象进行深度克隆。所以有一个权衡。
2021-03-21 13:26:08
我在我的浏览器(Chrome 59.0.3071.115)中针对上面 Dan 的回答测试了这个。它比 .slice() 慢了近 20 倍。n = 1000*1000; start = + new Date(); a = Array(n); var b = JSON.parse(JSON.stringify(a)) console.log(new Date() - start); // 221
2021-04-01 13:26:08
最糟糕的方式!仅在某些问题所有其他问题都不起作用时才使用。它很慢,资源密集,并且具有注释中已经提到的所有 JSON 限制。无法想象它是如何获得 25 票的。
2021-04-02 13:26:08
性能非常差,不能处理特殊对象,如 DOM、日期、正则表达式、函数……或原型对象。不支持循环引用。你永远不应该使用 JSON 进行深度克隆。
2021-04-03 13:26:08
var cloned_array = [].concat(target_array);
请解释这是做什么的。
2021-03-15 13:26:08
虽然此代码片段可能会回答这个问题,但它没有提供任何上下文来解释如何或为什么。考虑添加一两句话来解释你的答案。
2021-03-21 13:26:08
一个简单问题的简单答案,没有什么大故事要读。我喜欢这种答案+1
2021-03-26 13:26:08
我讨厌这种评论。它的作用一目了然!
2021-04-02 13:26:08
“我只问速度” - 这个答案没有说明速度。这是被问到的主要问题。Brandonscript 有一个很好的观点。需要更多信息才能将此视为答案。但如果这是一个更简单的问题,这将是一个很好的答案。
2021-04-09 13:26:08