Чтобы дублировать массив в 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 содержит ссылки на объекты, объекты не будут клонированы, а будут скопированы только ссылки, и поэтому оба массива будут иметь ссылки на одни и те же объекты. Но это не главное в этом вопросе.
Я спрашиваю только о скорости.
javascript
arrays
duplicates
copy
slice
Марко Демайо
источник
источник
Ответы:
Существует как минимум 5 (!) Способов клонировать массив:
Был поток huuuge BENCHMARKS , предоставляющий следующую информацию:
Для браузеров Blink
slice()
это самый быстрый метод,concat()
он немного медленнее иwhile loop
в 2,4 раза медленнее.для других браузеров
while loop
это самый быстрый метод, так как эти браузеры не имеют внутренних оптимизаций дляslice
иconcat
.Это остается верным в июле 2016 года.
Ниже приведены простые сценарии, которые вы можете скопировать и вставить в консоль браузера и запустить несколько раз, чтобы увидеть картинку. Они выводят миллисекунды, чем меньше, тем лучше.
в то время как цикл
кусочек
Обратите внимание, что эти методы будут клонировать сам объект Array, однако содержимое массива копируется по ссылке и не клонируется.
источник
splice
и вы будете удивлены (пока ...)A.map(function(e){return e;});
Технически
slice
это самый быстрый способ. Тем не менее , это даже быстрее, если вы добавите0
начальный индекс.быстрее чем
http://jsperf.com/cloning-arrays/3
источник
myArray.slice(0,myArray.length-1);
быстрее чемmyArray.slice(0);
?как насчет es6?
источник
[].concat(_slice.call(arguments))
arguments
взялась ... Я думаю, что ваш вывод из Babel объединяет несколько разных функций. Это более вероятноarr2 = [].concat(arr1)
.arr2 = [].conact(arr1)
отличается отarr2 = [...arr1]
.[...arr1]
синтаксис преобразует дыру вundefined
. Например,arr1 = Array(1); arr2 = [...arr1]; arr3 = [].concat(arr1); 0 in arr2 !== 0 in arr3
.n = 1000*1000; start = + new Date(); a = Array(n); b = [...a]; console.log(new Date() - start); // 168
[{a: 'a', b: {c: 'c'}}]
. Еслиc
значение изменяется в «дублированном» массиве, оно изменяется в исходном массиве, так как это просто ссылочная копия, а не клон.Самый простой способ глубокого клонирования массива или объекта:
источник
undefined
или каких-либоfunction
s. Оба из них будут преобразованыnull
для вас во времяJSON.stringify
процесса. Другие стратегии, такие как(['cool','array']).slice()
, не изменят их, но также не будут глубоко клонировать объекты в массиве. Таким образом, есть компромисс.n = 1000*1000; start = + new Date(); a = Array(n); var b = JSON.parse(JSON.stringify(a)) console.log(new Date() - start); // 221
источник
Я собрал короткую демонстрацию: http://jsbin.com/agugo3/edit
Мои результаты в Internet Explorer 8 - 156, 782 и 750, что говорит о
slice
том, что в этом случае гораздо быстрее.источник
a.map(e => e)
другая альтернатива для этой работы. На сегодняшний день.map()
очень быстро (почти так же быстро, как.slice(0)
) в Firefox, но не в Chrome.С другой стороны, если массив является многомерным, так как массивы являются объектами и объектами являются ссылочными типами, ни один из ломтиков или Concat методов не будет панацеей ... Так один правильный способ клонирования массива является изобретением ,
Array.prototype.clone()
как следующим образом .источник
🏁 Самый быстрый способ клонировать массив
Я сделал эту очень простую служебную функцию, чтобы проверить время, необходимое для клонирования массива. Он не на 100% надежен, однако может дать вам общее представление о том, сколько времени потребуется для клонирования существующего массива:
И опробовал другой подход:
ОБНОВЛЕНИЕ :
Примечание: из всех них единственным способом глубокого клонирования массива является использование
JSON.parse(JSON.stringify(arr))
.Тем не менее, не используйте вышеперечисленное, если ваш массив может включать функции, поскольку он будет возвращаться
null
.Спасибо @GilEpshtain за это обновление .
источник
arr => arr.slice()
самый быстрый.JSON.parse(JSON.stringify([function(){}]))
выйдет[null]
[...arr]
с4.653076171875ms
Chrome и8.565ms
Safari. Второй быстрый в Chrome есть функция ломтикаarr.slice()
с6.162109375ms
и в Safari второй находится[].concat(arr)
с13.018ms
.Взгляните на: ссылку . Дело не в скорости, а в комфорте. Кроме того, как вы можете видеть, вы можете использовать slice (0) только для примитивных типов .
Чтобы сделать независимую копию массива, а не копию ссылки на него, вы можете использовать метод среза массива.
Пример:
Источник: ссылка
источник
for
петле в вопросе.Как сказал @Dan: «Этот ответ быстро устареет. Используйте тесты для проверки реальной ситуации», есть один конкретный ответ от jsperf, у которого не было ответа для себя: while :
было 960 589 операций в секунду, второе место - 578
a.concat()
129 операций в секунду, что составляет 60%.Это последний Firefox (40) 64 бит.
@aleclarson создал новый, более надежный тест.
источник
ECMAScript 2015 способ с
Spread
оператором:Основные примеры:
Попробуйте в консоли браузера:
Ссылки
источник
Это зависит от браузера. Если вы посмотрите в записи блога Array.prototype.slice против ручного создания массива , есть приблизительное руководство по производительности каждого из них:
Результаты:
источник
arguments
не является правильным массивом, и он использует,call
чтобы заставитьslice
работать на коллекции. результаты могут вводить в заблуждение.Существует гораздо более чистое решение:
Проверка длины обязательна, потому что
Array
конструктор ведет себя по-разному, когда он вызывается только с одним аргументом.источник
splice()
, возможно. Но на самом деле, применять, и это все, но интуитивно понятно.Array.of
и игнорировать длину:Array.of.apply(Array, array)
Помните, что .slice () не будет работать для двумерных массивов. Вам понадобится такая функция:
источник
Это зависит от длины массива. Если длина массива <= 1000000, то
slice
иconcat
методы принимают примерно в то же время. Но когда вы даете более широкий диапазон,concat
метод побеждает.Например, попробуйте этот код:
Если вы установите длину original_array равным 1 000 000,
slice
метод иconcat
метод занимают примерно одинаковое время (3-4 мс, в зависимости от случайных чисел).Если вы установите длину original_array равным 10 000 000, то
slice
метод займет более 60 мс, аconcat
метод - более 20 мс.источник
dup.push
неправильноa5
, вместо этогоdup[i] =
следует использоватьПростое решение:
источник
Таким образом, чтобы избежать этих сценариев, используйте
источник
cloneNums[0][0]
в вашем примере распространило изменение наnums[0][0]
- но это потому, чтоnums[0][0]
это фактически объект, ссылка на который скопированаcloneNums
оператором распространения. Все это означает, что это поведение не повлияет на код, в который мы копируем по значению (int, string и т. Д.).Контрольное время!
Мои результаты:
Хром (двигатель V8):
Firefox (SpiderMonkey Engine):
источник
Быстрые способы дублировать массив в JavaScript в порядке:
#1: array1copy = [...array1];
#2: array1copy = array1.slice(0);
#3: array1copy = array1.slice();
Если ваши объекты массива содержат некоторое JSON-несериализуемое содержимое (функции, Number.POSITIVE_INFINITY и т. Д.), Лучше использовать
array1copy = JSON.parse(JSON.stringify(array1))
источник
Вы можете следовать этому коду. Неизменным образом массив клонов. Это идеальный способ клонирования массива
источник
В ES6 вы можете просто использовать синтаксис Spread .
Пример:
Обратите внимание, что оператор распространения создает совершенно новый массив, поэтому изменение одного не повлияет на другое.
Пример:
источник