Aby powielić tablicę w JavaScript: który z poniższych sposobów jest szybszy w użyciu?
Metoda krojenia
var dup_array = original_array.slice();
For
pętla
for(var i = 0, len = original_array.length; i < len; ++i)
dup_array[i] = original_array[i];
Wiem, że oba sposoby wykonują tylko płytką kopię : jeśli tablica_oryginalna zawiera odniesienia do obiektów, obiekty nie zostaną sklonowane, ale tylko odniesienia zostaną skopiowane, a zatem obie tablice będą miały odniesienia do tych samych obiektów. Ale nie o to chodzi w tym pytaniu.
Pytam tylko o szybkość.
javascript
arrays
duplicates
copy
slice
Marco Demaio
źródło
źródło
Odpowiedzi:
Istnieje co najmniej 5 (!) Sposobów klonowania tablicy:
Pojawił się ogromny wątek BENCHMARKS , zawierający następujące informacje:
w przypadku przeglądarek mrugających
slice()
jest to najszybsza metoda,concat()
jest nieco wolniejsza iwhile loop
jest 2,4 razy wolniejsza.dla innych przeglądarek
while loop
jest najszybszą metodą, ponieważ przeglądarki te nie mają wewnętrznych optymalizacji dlaslice
iconcat
.Tak jest w lipcu 2016 r.
Poniżej znajdują się proste skrypty, które można skopiować i wkleić w konsoli przeglądarki i uruchomić kilka razy, aby zobaczyć obraz. Generują milisekundy, im niższa, tym lepiej.
pętla while
plasterek
Należy pamiętać, że te metody sklonują sam obiekt Array, jednak zawartość tablicy jest kopiowana przez odniesienie i nie jest głęboko klonowana.
źródło
splice
a będziesz zaskoczony (podczas ...)A.map(function(e){return e;});
Technicznie
slice
jest to najszybszy sposób. Jednak dodanie0
indeksu początkowego jest jeszcze szybsze .jest szybszy niż
http://jsperf.com/cloning-arrays/3
źródło
myArray.slice(0,myArray.length-1);
szybszy niżmyArray.slice(0);
?co ze sposobem ES6?
źródło
[].concat(_slice.call(arguments))
arguments
pochodzi ... Myślę, że twoja produkcja babel łączy w sobie kilka różnych funkcji. Jest bardziej prawdopodobne, że tak będziearr2 = [].concat(arr1)
.arr2 = [].conact(arr1)
różni się odarr2 = [...arr1]
.[...arr1]
składnia zamieni dziurę wundefined
. Na przykładarr1 = 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'}}]
. Jeślic
wartość zostanie zmieniona w „zduplikowanej” tablicy, zmieni się ona w oryginalnej tablicy, ponieważ jest to tylko kopia referencyjna, a nie klon.Najłatwiejszy sposób na głębokie klonowanie tablicy lub obiektu:
źródło
undefined
ani żadnychfunction
s. Oba zostaną przekonwertowanenull
na Ciebie podczasJSON.stringify
procesu. Inne strategie, takie jak(['cool','array']).slice()
nie zmienią ich, ale również nie będą głęboko klonować obiektów w tablicy. Więc jest kompromis.n = 1000*1000; start = + new Date(); a = Array(n); var b = JSON.parse(JSON.stringify(a)) console.log(new Date() - start); // 221
źródło
Przygotowałem szybkie demo: http://jsbin.com/agugo3/edit
Moje wyniki w Internet Explorerze 8 to 156, 782 i 750, co wskazuje, że
slice
w tym przypadku jest znacznie szybsze.źródło
a.map(e => e)
to kolejna alternatywa dla tej pracy. Na dzień dzisiejszy.map()
jest bardzo szybki (prawie tak szybki.slice(0)
) w Firefoksie, ale nie w Chrome.Z drugiej strony, jeśli tablica jest wielowymiarowa, ponieważ tablice są obiekty i przedmioty są typy referencyjne, żadna z metod plasterek lub Concat będzie leczyć ... Więc jeden właściwy sposób klonowania tablicę jest wynalazkiem
Array.prototype.clone()
jako następuje.źródło
🏁 Najszybszy sposób na klonowanie tablicy
Zrobiłem tę bardzo prostą funkcję narzędzia do testowania czasu potrzebnego do sklonowania tablicy. Nie jest w 100% wiarygodny, jednak może dać ci ogólny pomysł na to, ile czasu zajmuje klonowanie istniejącej tablicy:
I przetestowałem inne podejście:
AKTUALIZACJA :
Uwaga: spośród nich jedynym sposobem głębokiego klonowania tablicy jest użycie
JSON.parse(JSON.stringify(arr))
.To powiedziawszy, nie używaj powyższego, jeśli tablica może zawierać funkcje, ponieważ zwróci
null
.Dziękuję @GilEpshtain za tę aktualizację .
źródło
arr => arr.slice()
jest najszybszy.JSON.parse(JSON.stringify([function(){}]))
wyświetli[null]
[...arr]
ze4.653076171875ms
w Chrome i8.565ms
Safari. Druga szybko w Chrome jest funkcja plasterarr.slice()
z6.162109375ms
a drugi jest w Safari[].concat(arr)
z13.018ms
.Spójrz na: link . Nie chodzi o szybkość, ale o komfort. Poza tym, jak widać, można używać wycinka (0) tylko na typach pierwotnych .
Aby utworzyć niezależną kopię tablicy zamiast kopii odwołania do niej, możesz użyć metody wycinania tablic.
Przykład:
Źródło: link
źródło
for
pętli w pytaniu, jak również.Jak powiedział @Dan „Ta odpowiedź szybko staje się przestarzała. Użyj testów porównawczych, aby sprawdzić rzeczywistą sytuację”, jest jedna konkretna odpowiedź od jsperf, która nie ma odpowiedzi dla siebie: podczas gdy :
miał 960.589 operacji na sekundę z drugim miejscem
a.concat()
na poziomie 578,129 operacji na sekundę, co stanowi 60%.To najnowszy 64-bitowy Firefox (40).
@aleclarson stworzył nowy, bardziej niezawodny test porównawczy.
źródło
Sposób ECMAScript 2015 z
Spread
operatorem:Podstawowe przykłady:
Wypróbuj w konsoli przeglądarki:
Bibliografia
źródło
To zależy od przeglądarki. Jeśli spojrzysz na post na blogu Array.prototype.slice vs. ręczne tworzenie tablic , istnieje przybliżony przewodnik po wydajności każdego z nich:
Wyniki:
źródło
arguments
nie jest odpowiednią tablicą i używa,call
aby wymusićslice
uruchomienie kolekcji. wyniki mogą być mylące.Istnieje o wiele czystsze rozwiązanie:
Kontrola długości jest wymagana, ponieważ
Array
konstruktor zachowuje się inaczej, gdy jest wywoływany z dokładnie jednym argumentem.źródło
splice()
Może bardziej semantyczny niż . Ale naprawdę, zastosuj, a to wszystko jest prawie intuicyjne.Array.of
i zignorować długość:Array.of.apply(Array, array)
Pamiętaj, że .slice () nie będzie działać dla tablic dwuwymiarowych. Potrzebujesz takiej funkcji:
źródło
To zależy od długości tablicy. Jeśli długość tablicy wynosi <= 1 000 000, metody
slice
iconcat
zajmują mniej więcej ten sam czas. Ale gdy podasz szerszy zakres,concat
metoda wygrywa.Na przykład wypróbuj ten kod:
Jeśli ustawisz długość original_array na 1 000 000,
slice
metoda iconcat
metoda zajmą mniej więcej ten sam czas (3-4 ms, w zależności od liczb losowych).Jeśli ustawisz długość pierwotnej tablicy na 10 000 000, wówczas
slice
metoda zajmuje ponad 60 ms, aconcat
metoda trwa ponad 20 ms.źródło
dup.push
jest źle wa5
, zamiast tegodup[i] =
należy użyćProste rozwiązanie:
źródło
Aby uniknąć tych scenariuszy, użyj
źródło
cloneNums[0][0]
w twoim przykładzie propagowała zmianęnums[0][0]
- ale dzieje się tak, ponieważnums[0][0]
jest to obiekt, do którego odwołanie jest kopiowanecloneNums
przez operator rozkładania. Wszystko to znaczy, że to zachowanie nie wpłynie na kod, w którym kopiujemy według wartości (literały int, string itp.).Czas testu!
Moje wyniki:
Chrome (silnik V8):
Firefox (silnik SpiderMonkey):
źródło
Szybkie sposoby duplikowania tablicy w JavaScript w kolejności:
#1: array1copy = [...array1];
#2: array1copy = array1.slice(0);
#3: array1copy = array1.slice();
Jeśli obiekty tablicowe zawierają pewną zawartość, która nie jest serializowana JSON (funkcje, Number.POSITIVE_INFINITY itp.), Lepiej użyć
array1copy = JSON.parse(JSON.stringify(array1))
źródło
Możesz śledzić ten kod. Niezmienny sposób klonowania tablicy. Jest to idealny sposób na klonowanie macierzy
źródło
W ES6 możesz po prostu użyć składni Spread .
Przykład:
Pamiętaj, że operator rozkładania generuje zupełnie nową tablicę, więc modyfikowanie jednej nie wpłynie na drugą.
Przykład:
źródło