Самый быстрый способ дублирования массива в JavaScript - срез против цикла "за"

Чтобы дублировать массив в 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 содержит ссылки на объекты, объекты не будут клонированы, но будут копироваться только ссылки, и поэтому оба массива будут иметь ссылки на одни и те же объекты. Но это не вопрос этого вопроса.

Я прошу только о скорости.

+552
20 окт. '10 в 13:43
источник поделиться
18 ответов

Существует как минимум 5 (!) Способов клонировать массив:

  • петля
  • ломтик
  • Array.from()
  • CONCAT
  • оператор распространения (FASTEST)

Был поток huuuge BENCHMARKS, предоставляющий следующую информацию:

  • для браузеров blink slice() - самый быстрый метод, concat() - немного медленнее, а while loop - в 2,4 раза медленнее.

  • для других браузеров while loop - это самый быстрый метод, поскольку в этих браузерах нет внутренних оптимизаций для slice и concat.

Это остается верным в июле 2016 года.

Ниже приведены простые сценарии, которые вы можете скопировать и вставить в консоль браузера и запустить несколько раз, чтобы увидеть картинку. Они выводят миллисекунды, чем меньше, тем лучше.

в то время как цикл

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
+709
12 дек. '13 в 15:42
источник

Связанные вопросы


Похожие вопросы

Технически slice это самый быстрый способ. Тем не менее, это даже быстрее, если вы добавите индекс начала 0.

myArray.slice(0);

быстрее чем

myArray.slice();

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

+206
02 февр. '14 в 18:11
источник

как насчет пути es6?

arr2 = [...arr1];
+114
06 июл. '15 в 16:34
источник

Самый простой способ глубокого клонирования массива или объекта:

var dup_array = JSON.parse(JSON.stringify(original_array))
+42
05 мая '14 в 20:23
источник
var cloned_array = [].concat(target_array);
+27
05 окт. '16 в 12:00
источник

Я собрал быстрое демо: http://jsbin.com/agugo3/edit

Мои результаты в Internet Explorer 8 - 156, 782 и 750, что указывает на то, что в этом случае slice намного быстрее.

+25
20 окт. '10 в 14:06
источник

a.map(e => e) является другой альтернативой для этой работы. На сегодняшний день .map() работает очень быстро (почти так же быстро, как .slice(0)) в Firefox, но не в Chrome.

С другой стороны, если массив является многомерным, поскольку массивы являются объектами и объектами являются ссылочными типами, ни один из методов среза или concat не будет излечением... Таким образом, один правильный способ клонирования массива - это изобретение 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));
+19
28 мая '16 в 21:32
источник

Самый быстрый способ клонировать массив

Я сделал эту очень простую служебную функцию, чтобы проверить время, необходимое для клонирования массива. Он не на 100% надежен, однако может дать вам общее представление о том, сколько времени потребуется для клонирования существующего массива:

function clone(fn) {
    const arr = [...Array(1000000)];
    console.time('timer');
    fn(arr);
    console.timeEnd('timer');
}

И опробовал другой подход:

1)   5.79ms -> clone(arr => Object.values(arr));
2)   7.23ms -> clone(arr => [].concat(arr));
3)   9.13ms -> clone(arr => arr.slice());
4)  24.04ms -> clone(arr => { const a = []; for (let val of arr) { a.push(val); } return a; });
5)  30.02ms -> clone(arr => [...arr]);
6)  39.72ms -> clone(arr => JSON.parse(JSON.stringify(arr)));
7)  99.80ms -> clone(arr => arr.map(i => i));
8) 259.29ms -> clone(arr => Object.assign([], arr));
9) Maximum call stack size exceeded -> clone(arr => Array.of(...arr));

ОБНОВЛЕНИЕ:
Примечание: из всех них единственным способом глубокого клонирования массива является использование JSON.parse(JSON.stringify(arr)).

Тем не менее, не используйте выше, если ваш массив может включать функции, поскольку он будет возвращать null.
Спасибо @GilEpshtain за это обновление.

+11
22 окт. '18 в 12:50
источник

Это зависит от браузера. Если вы посмотрите в блоге Array.prototype.slice против создания массива вручную, есть приблизительное руководство по производительности каждого из них:

Enter image description here

Результаты:

Enter image description here

+7
20 окт. '10 в 13:55
источник

Существует гораздо более чистое решение:

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

Требуется проверка длины, потому что конструктор Array ведет себя по-разному, когда он вызывается только с одним аргументом.

+6
28 апр. '14 в 13:31
источник

Поскольку @Dan сказал: "Этот ответ быстро устареет. Используйте контрольные показатели, чтобы проверить реальную ситуацию", есть один конкретный ответ от jsperf, который не получил ответа для себя: while:

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

имел 960 589 оп/сек с бегуном a.concat() при 578,129 оп/сек, что составляет 60%.

Это самый последний Firefox (40) 64 бит.


@aleclarson создал новый, более надежный бенчмарк.

+6
27 авг. '15 в 15:33
источник

Взгляните на: ссылку. Это не о скорости, а о комфорте. Кроме того, как вы можете видеть, вы можете использовать только срез (0) для примитивных типов.

Чтобы сделать независимую копию массива, а не копию подтверждения, вы можете использовать метод среза массива.

Пример:

Чтобы сделать независимую копию массива, а не копию подтверждения, вы можете использовать метод среза массива.

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

Источник: ссылка

+6
20 окт. '10 в 13:52
источник

Помните.slice() не будет работать для двумерных массивов. Вам понадобится такая функция:

function copy(array) {
  return array.map(function(arr) {
    return arr.slice();
  });
}
+6
21 янв. '16 в 13:02
источник

Это зависит от длины массива. Если длина массива <= 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 мс, в зависимости от случайных чисел).

Если вы установите длину original_array на 10 000 000, то метод slice занимает более 60 мс, а метод concat занимает более 20 мс.

+5
18 нояб. '15 в 7:35
источник

ECMAScript 2015 с оператором Spread:

Основные примеры:

var copyOfOldArray = [...oldArray]
var twoArraysBecomeOne = [...firstArray, ..seccondArray]

Попробуйте в консоли браузера:

var oldArray = [1, 2, 3]
var copyOfOldArray = [...oldArray]
console.log(oldArray)
console.log(copyOfOldArray)

var firstArray = [5, 6, 7]
var seccondArray = ["a", "b", "c"]
var twoArraysBecomOne = [...firstArray, ...seccondArray]
console.log(twoArraysBecomOne);

Рекомендации

+4
16 дек. '17 в 8:24
источник

Простое решение:

original = [1,2,3]
cloned = original.map(x=>x)
+3
16 авг. '17 в 0:24
источник

У меня есть вопрос по этому вопросу. Пожалуйста, не отрицайте это. Я просто спрашиваю мнение других, а не предлагаю ответ. Будет ли следующий подход ответить на вопрос оригинального плаката?

const a = [1, 2, 3, 4, 5]
const b = Object.assign([], a)
0
09 дек. '18 в 8:27
источник
        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 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);
0
07 июн. '19 в 17:39
источник

Посмотрите другие вопросы по меткам или Задайте вопрос