JavaScript最快的方式来复制一个数组 – 切片VS for循环

为了在Javascript中复制数组,

有没有人知道(也许testing)是否更快使用:

切片方法:

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包含对象的引用,对象将不会被克隆,但只有引用将被复制,因此这两个数组将引用相同的对象。 但这不是这个问题的重点。

我只问速度。

至less有5 (!)个方法来克隆一个数组:

  • 循环
  • Array.from()
  • CONCAT
  • 传播运营商等(如此缓慢,现在忘记)

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

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

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

这在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); 

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

 myArray.slice(0); 

比快,

 myArray.slice(); 

http://jsperf.com/cloning-arrays/3

那么es6的方式呢?

 arr2 = [...arr1]; 

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

 var dup_array = JSON.parse(JSON.stringify(original_array)) 

我放了一个快速演示。 http://jsbin.com/agugo3/edit

我在IE8上的结果是156/782/750,这表明slice在这种情况下要快得多。

 var cloned_array = [].concat(target_array); 

由于没有人提到a.map(e => e)是这个工作的另一种select。 截至今天.map()在FF中速度非常快(几乎和.slice(0)一样快),但在Chrome中却没有。

另一方面,如果一个数组是多维的,因为数组是对象而对象是引用types,那么切片或连接方法都不会成为一种解决方法。因此,克隆数组的一种正确方法是发明Array.prototype.clone()如下;

 Array.prototype.clone = function(){ return this.map(e => Array.isArray(e) ? e.clone() : e); }; var arr = [ 1, 2, 3, 4, [ 1, 2, [ 1, 2, 3 ], 4 , 5], 6 ], brr = arr.clone(); brr[4][2][1] = "two"; console.log(JSON.stringify(arr)); console.log(JSON.stringify(brr)); 

正如@丹说:“这个答案变得过时了,使用基准来检查实际情况”,jsperf有一个具体的答案,它本身没有答案: while

 var i = a.length; while(i--) { b[i] = a[i]; } 

秒为960,589 ops / sec,runnerup a.concat()为578,129 ops / sec,为60%。

这是最新的Firefox(40)64位。

这取决于浏览器。 如果你看下面的链接,有一个粗略的指导每个的性能: http : //weblogs.asp.net/alexeigorkov/archive/2008/02/18/array-prototype-slice-vs-manual-array-creation的.aspx

在这里输入图像描述

结果:

在这里输入图像描述

还有更多干净的解决scheme:

 var srcArray = [1, 2, 3]; var clonedArray = srcArray.length === 1 ? [srcArray[0]] : Array.apply(this, srcArray); 

长度检查是必需的,因为当使用一个参数调用Array构造函数时,其行为会有所不同。

看看: 链接 。 这不是速度,而是舒适。 此外,正如你所看到的,你只能在原始types上使用slice(0)

要创build一个数组的独立副本而不是副本,可以使用数组切片方法。

例:

要创build一个数组的独立副本而不是副本,可以使用数组切片方法。

 var oldArray = ["mip", "map", "mop"]; var newArray = oldArray.slice(); 

复制或克隆对象:

 function cloneObject(source) { for (i in source) { if (typeof source[i] == 'source') { this[i] = new cloneObject(source[i]); } else{ this[i] = source[i]; } } } var obj1= {bla:'blabla',foo:'foofoo',etc:'etc'}; var obj2= new cloneObject(obj1); 

来源: 链接

请记住.slice()不适用于二维数组。 你需要一个这样的function:

 function copy(array) { return array.map(function(arr) { return arr.slice(); }); } 

这取决于数组的长度。 如果数组长度<= 1000000,则slice和concat方法大致同时进行。 但是,当你给更多的范围,concat方法获胜。 例如试试这个代码

 var original_array = []; for(var i = 0; i < 10000000; i ++) { original_array.push( Math.floor(Math.random() * 1000000 + 1)); } function a1() { var dup = []; var start = Date.now(); dup = original_array.slice(); var end = Date.now(); console.log('slice method takes ' + (end - start) + ' ms'); } function a2() { var dup = []; var start = Date.now(); dup = original_array.concat([]); var end = Date.now(); console.log('concat method takes ' + (end - start) + ' ms'); } function a3() { var dup = []; var start = Date.now(); for(var i = 0; i < original_array.length; i ++) { dup.push(original_array[i]); } var end = Date.now(); console.log('for loop with push method takes ' + (end - start) + ' ms'); } function a4() { var dup = []; var start = Date.now(); for(var i = 0; i < original_array.length; i ++) { dup[i] = original_array[i]; } var end = Date.now(); console.log('for loop with = method takes ' + (end - start) + ' ms'); } function a5() { var dup = new Array(original_array.length) var start = Date.now(); for(var i = 0; i < original_array.length; i ++) { dup.push(original_array[i]); } var end = Date.now(); console.log('for loop with = method and array constructor takes ' + (end - start) + ' ms'); } a1(); a2(); a3(); a4(); a5(); 

如果给出original_array的长度为1000000,slice方法和concat方法大约是相同的时间(3-4ms取决于随机数)。

如果你给original_array 10000000的长度,那么slice方法占用60ms,concat方法占用20ms。

简单的解决scheme:

 original = [1,2,3] cloned = original.map(x=>x)