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

片的方法

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

我只是在问速度。


当前回答

它取决于数组的长度。如果数组长度<= 1,000,000,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的长度设置为1,000,000,slice方法和concat方法大约需要相同的时间(3-4 ms,取决于随机数)。

如果将original_array的长度设置为10,000,000,则slice方法需要超过60 ms, concat方法需要超过20 ms。

其他回答

我整理了一个简短的演示:http://jsbin.com/agugo3/edit

我在Internet Explorer 8上的结果是156、782和750,这表明切片在这种情况下要快得多。

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

var dup_array = JSON.parse(JSON.stringify(original_array))
        const arr = ['1', '2', '3'];

         // Old way
        const cloneArr = arr.slice();

        // ES6 way
        const cloneArrES6 = [...arr];

// But problem with 3rd approach is that if you are using muti-dimensional 
 // array, then only first level is copied

        const nums = [
              [1, 2], 
              [10],
         ];

        const cloneNums = [...nums];

// Let's change the first item in the first nested item in our cloned array.

        cloneNums[0][0] = '8';

        console.log(cloneNums);
           // [ [ '8', 2 ], [ 10 ], [ 300 ] ]

        // NOOooo, the original is also affected
        console.log(nums);
          // [ [ '8', 2 ], [ 10 ], [ 300 ] ]

所以,为了避免这些情况的发生,使用

        const arr = ['1', '2', '3'];

        const cloneArr = Array.from(arr);

有一个更干净的解决方案:

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

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

如果你想在JS中获得一个REAL克隆对象/数组,其中包含所有属性和子对象的克隆引用:

export function clone(arr) {
    return JSON.parse(JSON.stringify(arr))
}

所有其他操作都不会创建克隆,因为它们只是改变根元素的基址,而不是所包含对象的基址。

除了递归遍历对象树。

对于一个简单的副本,这些是可以的。对于存储地址相关的操作,我建议(在大多数其他情况下,因为这是快速的!)类型转换为字符串和返回在一个完整的新对象。