Podczas kopiowania tablicy w JavaScript do innej tablicy:
var arr1 = ['a','b','c'];
var arr2 = arr1;
arr2.push('d'); //Now, arr1 = ['a','b','c','d']
Uświadomiłem sobie, że arr2
odnosi się to do tej samej tablicy arr1
, a nie do nowej, niezależnej tablicy. Jak mogę skopiować tablicę, aby uzyskać dwie niezależne tablice?
javascript
arrays
Dan
źródło
źródło
slice
isplice
operacje oraz nowego operatora rozprzestrzeniania iArray.from
mamy znacznie wolniejszą implementację. Spójrz na perfjs.fnfovar arr2 = arr1.splice();
do głębokiej kopii, ale technika ta nie będzie działać, jeśli elementy macierzy zawierają struktury dosłownych (tj[]
lub{}
) lub obiektów prototypowych (tjfunction () {}
,new
itp). Zobacz moje odpowiedzi poniżej, aby uzyskać dalsze rozwiązania.let arr2 = [...arr1];
developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…Odpowiedzi:
Użyj tego:
Zasadniczo
slice()
operacja klonuje tablicę i zwraca odwołanie do nowej tablicy.Pamiętaj również, że:
W przypadku odniesień, ciągów i liczb (a nie rzeczywistego obiektu)
slice()
kopiuje odniesienia do obiektu do nowej tablicy. Zarówno oryginalna, jak i nowa tablica odnoszą się do tego samego obiektu. Jeśli obiekt, do którego istnieje odwołanie, ulega zmianie, zmiany są widoczne zarówno dla nowych, jak i oryginalnych tablic.Prymitywy takie jak łańcuchy i liczby są niezmienne, więc zmiany w łańcuchu lub liczbie są niemożliwe.
źródło
.slice()
z tym.splice()
, co daje pustą tablicę. Duża różnica.W JavaScript, techniki głębokiego kopiowania zależą od elementów w tablicy. Zacznijmy od tego.
Trzy rodzaje elementów
Elementami mogą być: wartości dosłowne, struktury dosłowne lub prototypy.
Z tych elementów możemy stworzyć trzy typy tablic.
Techniki głębokiego kopiowania zależą od trzech typów tablic
W oparciu o typy elementów w tablicy, możemy użyć różnych technik do głębokiego kopiowania.
Tablica dosłownych wartościach (type1) , , , i techniki mogą być wykorzystywane do głębokich kopiowanie tablic z wartościami dosłownych (logiczna, numer i napis) tylko; gdzie operator Spread ma najlepszą wydajność ( https://measurethat.net/Benchmarks/Show/4281/0/spread-array-performance-vs-slice-splice-concat ).
[...myArray]
myArray.splice(0)
myArray.slice()
myArray.concat()
[...myArray]
Tablica dosłownych wartościach (type1) i dosłownych strukturach (TYPE2) technika może być użyta do głębokiego kopiowanie wartości dosłownych (Boolean, liczba, ciąg) i struktur dosłownych (array, obiekt), ale nie prototyp obiektów.
JSON.parse(JSON.stringify(myArray))
Wszystkie tablice (typ 1, typ 2, typ 3) Techniki
jQuery
$.extend(myArray)
można używać do głębokiego kopiowania wszystkich typów tablic. Biblioteki takie jak Underscore i Lo-dash oferują podobne funkcje głębokiego kopiowania do jQuery$.extend()
, ale mają niższą wydajność. Co bardziej zaskakujące,$.extend()
ma wyższą wydajność niżJSON.parse(JSON.stringify(myArray))
technika http://jsperf.com/js-deep-copy/15 .A dla programistów, którzy unikają bibliotek stron trzecich (takich jak jQuery), możesz użyć następującej funkcji niestandardowej; który ma wyższą wydajność niż $ .extend i kopiuje głęboko wszystkie tablice.
Aby odpowiedzieć na pytanie ...
Pytanie
Odpowiedź
Ponieważ
arr1
jest to tablica wartości literalnych (wartość logiczna, liczba lub łańcuch), możesz użyć dowolnej techniki głębokiego kopiowania omówionej powyżej, w której operator rozkładania...
ma najwyższą wydajność.źródło
arr1
. To bardzo rzadkie, że tak będzie. Używaniesplice
obliteratówarr1
, więc to wcale nie jest kopia. UżycieJSON
zakończy się niepowodzeniem, jeśli którakolwiek z wartości w tablicy to Funkcje lub prototypy (takie jak aDate
).[0,"1",{2:3},function random() {return 4;}, [[5,6,7],[8,9,10],[11,12,13]]]
żadną inną tablicą.Za pomocą rozkładówek
...
można kopiować tablice.const itemsCopy = [...items];
Również jeśli chcesz utworzyć nową tablicę, której częścią jest już istniejąca:
Rozszerzenia tablic są teraz obsługiwane we wszystkich głównych przeglądarkach, ale jeśli potrzebujesz starszej obsługi, użyj maszynopisu lub babel i skompiluj do ES5.
Więcej informacji o spreadach
źródło
JQuery nie jest potrzebne ... Przykład roboczy
Spowoduje to skopiowanie tablicy od pozycji początkowej
0
do końca tablicy.Ważne jest, aby pamiętać, że będzie działać zgodnie z oczekiwaniami dla typów pierwotnych (ciąg, liczba itp.), A także wyjaśnić oczekiwane zachowanie dla typów odniesienia ...
Jeśli masz tablicę typów odwołań, powiedz typu
Object
. Tablica zostanie skopiowana, ale obie tablice będą zawierać odniesienia do tych samychObject
. W takim przypadku wydaje się, że tablica jest kopiowana przez odniesienie, nawet jeśli tablica jest faktycznie kopiowana.źródło
var arr2 = JSON.stringify(arr1); arr2 = JSON.parse(arr2);
Alternatywą
slice
jestconcat
, która może być używana na 2 sposoby. Pierwszy z nich jest być może bardziej czytelny, ponieważ zamierzone zachowanie jest bardzo jasne:Druga metoda to:
Cohen (w komentarzach) zauważył, że ta ostatnia metoda ma lepszą wydajność .
Działa to tak, że
concat
metoda tworzy nową tablicę składającą się z elementów w obiekcie, do którego jest wywoływana, a następnie elementów dowolnych tablic przekazywanych do niej jako argumenty. Więc gdy nie zostaną przekazane żadne argumenty, po prostu kopiuje tablicę.Lee Penkman, również w komentarzach, zwraca uwagę, że jeśli istnieje szansa
array1
jestundefined
, można powrócić pustą tablicę, co następuje:Lub, dla drugiej metody:
Należy pamiętać, że można to zrobić także z
slice
:var array2 = (array1 || []).slice();
.źródło
[].concat(array1)
zwraca[array1]
np. Jeśli otrzymasz jej niezdefiniowaną wartość[undefined]
. Czasami tak robięvar array2 = [].concat(array1 || []);
Tak to zrobiłem po wypróbowaniu wielu podejść:
Spowoduje to utworzenie nowej głębokiej kopii niezwiązanej z pierwszą (nie płytkiej kopii).
To oczywiście nie sklonuje zdarzeń i funkcji, ale dobrą rzeczą jest to, że możesz to zrobić w jednym wierszu i można go użyć do dowolnego rodzaju obiektu (tablic, ciągów, liczb, obiektów ...)
źródło
Date
prototyp. Ponadtoundefined
s są konwertowane nanull
s.Niektóre z wymienionych metod działają dobrze podczas pracy z prostymi typami danych, takimi jak liczba lub łańcuch, ale gdy tablica zawiera inne obiekty, metody te zawodzą. Kiedy próbujemy przekazać dowolny obiekt z jednej tablicy do drugiej, jest on przekazywany jako odniesienie, a nie obiekt.
Dodaj następujący kod do pliku JavaScript:
I po prostu użyj
To będzie działać.
źródło
.slice()
nadal działa dobrze, nawet jeśli masz obiekty w tablicy: jsfiddle.net/edelman/k525gOd ES2015
źródło
Osobiście uważam, że Array.from jest bardziej czytelnym rozwiązaniem. Nawiasem mówiąc, uważaj tylko na obsługę przeglądarki.
źródło
.slice()
Rozwiązanie jest całkowicie unintuitive. Dzięki za to.Ważny!
Większość odpowiedzi tutaj działa w określonych przypadkach .
Jeśli nie interesują Cię głębokie / zagnieżdżone obiekty i rekwizyty użyj ( ES6 ):
let clonedArray = [...array]
ale jeśli chcesz wykonać głęboki klon, użyj tego:
let cloneArray = JSON.parse(JSON.stringify(array))
Dla użytkowników lodash:
let clonedArray = _.clone(array)
dokumentacjai
let clonedArray = _.cloneDeep(array)
dokumentacjaźródło
Jeśli pracujesz w środowisku ECMAScript 6 , korzystając z operatora Spread możesz to zrobić w następujący sposób:
źródło
Dodanie do rozwiązania array.slice (); pamiętaj, że jeśli masz wielowymiarową tablicę, tablice podrzędne zostaną skopiowane przez referencje. To, co możesz zrobić, to zapętlić i pokroić () każdą pod-macierz osobno
te same rzeczy dotyczą tablicy obiektów, zostaną one skopiowane przez odniesienie, musisz je skopiować ręcznie
źródło
Wartości pierwotne są zawsze przekazywane przez jego wartość (kopiowane). Wartości złożone są jednak przekazywane przez odniesienie.
Jak więc skopiować ten arr?
Skopiuj tablicę w ES6
Skopiuj n Tablicę w ES5
Dlaczego `let arrCopy = arr` nie przekazuje wartości?
Przekazywanie jednej zmiennej do drugiej w przypadku wartości złożonych, takich jak Object / Array, zachowuje się inaczej. Używając operatora asign na wartościach copand przekazujemy odwołanie do obiektu. Dlatego wartość obu tablic zmienia się podczas usuwania / dodawania elementów tablic.
Wyjątki:
Gdy przypisujesz nową wartość do zmiennej, zmieniasz samą referencję i nie wpływa ona na oryginalny obiekt / tablicę.
Czytaj więcej
źródło
Jak wiemy w tablicach i obiektach JavaScript są referencyjne, ale w jaki sposób możemy skopiować tablicę bez zmiany oryginalnej tablicy później?
Oto kilka sposobów, aby to zrobić:
Wyobraź sobie, że w kodzie mamy tę tablicę:
1) Zapętlanie tablicy przez funkcję i zwracanie nowej tablicy, jak poniżej:
2) Przy użyciu metody wycinania plasterek służy do wycinania części tablicy, wycina część tablicy bez dotykania oryginału, w wycinku, jeśli nie określi się początku i końca tablicy, wycina całość tablicę i w zasadzie wykonaj pełną kopię tablicy, dzięki czemu możemy łatwo powiedzieć:
3) Również metoda kontaktowa, służy do scalenia dwóch tablic, ale możemy po prostu określić jedną z tablic, a następnie w zasadzie wykonać kopię wartości w nowej tablicy kontaktowej:
4) Metoda strunizacji i parsowania, nie jest zalecana, ale może być łatwym sposobem kopiowania tablicy i obiektów:
5) Metoda Array.from, nie jest to powszechnie obsługiwane, przed użyciem sprawdź obsługę w różnych przeglądarkach:
6) Sposób ECMA6, również nie w pełni obsługiwany, ale babelJs może ci pomóc, jeśli chcesz dokonać transpozycji:
źródło
Teraz możesz wykonać dowolną z poniższych czynności, aby utworzyć kopię tablicy.
LUB
LUB
LUB
LUB
Teraz, jeśli zmienię
Zatem a wynosi [1,2,3,5], ale b jest nadal [1,2,3], ponieważ ma inne odniesienie.
Ale myślę, że we wszystkich powyższych metodach Array.from jest lepszy i stworzony głównie do kopiowania tablicy.
źródło
Osobiście wolałbym ten sposób:
źródło
W moim szczególnym przypadku musiałem upewnić się, że tablica pozostała nienaruszona, więc zadziałało to dla mnie:
źródło
Utwórz kopię wielowymiarowej tablicy / obiektu:
Dzięki James Padolsey za tę funkcję.
Źródło: tutaj
źródło
Dan, nie musisz używać fantazyjnych sztuczek. Wystarczy, że zrobisz kopię arr1.
Teraz
arr1
iarr2
dwa różne zmienne przechowywanym w oddzielnych stosach. Sprawdź to na jsfiddle .źródło
var arr2 = [arr1];
.).Kiedy chcemy skopiować tablicę za pomocą operatora przypisania (
=
), nie tworzy ona kopii, a jedynie kopiuje wskaźnik / odwołanie do tablicy. Na przykład:Często podczas przekształcania danych chcemy zachować nienaruszoną naszą początkową strukturę danych (np. Macierz). Robimy to, robiąc dokładną kopię naszej tablicy, aby ta mogła zostać przekształcona, podczas gdy początkowa pozostaje nienaruszona.
Sposoby kopiowania tablicy:
Zachowaj ostrożność, gdy tablice lub obiekty są zagnieżdżone !:
Po zagnieżdżeniu tablic wartości są kopiowane przez odniesienie. Oto przykład, w jaki sposób może to prowadzić do problemów:
Dlatego nie używaj tych metod, gdy w tablicy znajdują się obiekty lub tablice, które chcesz skopiować. tzn. używaj tych metod tylko do tablic prymitywów.
Jeśli chcesz głęboko sklonować użycie tablicy javascript
JSON.parse
w połączeniu zJSON.stringify
:Wykonanie kopiowania:
Który wybieramy dla uzyskania optymalnej wydajności. Okazuje się, że najbardziej szczegółowa metoda,
for
pętla ma najwyższą wydajność. Użyjfor
pętli do naprawdę intensywnego kopiowania procesora (duże / wiele tablic).Następnie
.slice()
metoda ma również przyzwoitą wydajność, jest również mniej szczegółowa i łatwiejsza do wdrożenia przez programistę. Proponuję używać.slice()
do codziennego kopiowania tablic, które nie wymagają dużego obciążenia procesora. Unikaj także korzystania zJSON.parse(JSON.stringify(arr))
(dużego obciążenia), jeśli nie jest wymagany głęboki klon, a wydajność stanowi problem.Test wydajności źródła
źródło
Jeśli tablica zawiera elementy pierwotnego typu danych, takie jak int, char lub string itp., Możesz użyć jednej z tych metod, która zwraca kopię oryginalnej tablicy, takiej jak .slice () lub .map () lub operator rozkładania ( dzięki ES6).
lub
lub
ALE jeśli twoja tablica zawiera złożone elementy, takie jak obiekty (lub tablice) lub więcej zagnieżdżonych obiektów , musisz upewnić się, że wykonujesz kopię wszystkich elementów z najwyższego poziomu na ostatni poziom odniesienia do wewnętrznej obiekty będą używane, co oznacza, że zmiana wartości w elementach_obiektu w nowej_tablicy będzie nadal wpływać na starą_tablicę. Możesz nazwać tę metodę kopiowania na każdym poziomie jako GŁĘBOKIE KOPIOWANIE GŁĘBOKIE starej tablicy.
Do głębokiego kopiowania można użyć wyżej wymienionych metod dla prymitywnych typów danych na każdym poziomie w zależności od rodzaju danych lub można użyć tej kosztownej metody (wspomnianej poniżej) do wykonania głębokiej kopii bez większego nakładu pracy.
Istnieje wiele innych metod, których można użyć w zależności od wymagań. Wspomniałem tylko o niektórych z nich, aby dać ogólny obraz tego, co się dzieje, gdy próbujemy skopiować tablicę na drugą pod względem wartości .
źródło
Jeśli chcesz utworzyć nową kopię obiektu lub tablicy, musisz jawnie skopiować właściwości obiektu lub elementów tablicy, na przykład:
Możesz wyszukiwać w Google więcej informacji o niezmiennych pierwotnych wartościach i odwoływalnych obiektach.
źródło
Za pomocą głębokiej kopii jQuery można wykonać w następujący sposób:
źródło
Możesz także użyć operatora rozkładania ES6 do skopiowania macierzy
źródło
Oto kilka innych sposobów kopiowania:
źródło
Możesz używać ES6 z rozszerzonym Opeartor, jest to prostsze.
Istnieją ograniczenia .. sprawdź dokumenty Składnia rozprzestrzeniania @ mozilla
źródło
Szybkie przykłady:
źródło
Oto wariant:
źródło
toSource
nie jest standardowa i na przykład nie będzie działać w Chrome.Jest nowo wprowadzony
Array.from
, ale niestety, w chwili pisania tego tekstu jest obsługiwany tylko w najnowszych wersjach Firefoksa (32 i nowszych). Można go po prostu użyć w następujący sposób:Referencja: tutaj
Lub
Array.prototype.map
może być używany z funkcją tożsamości:Referencja: tutaj
źródło
Array.from
, która jest teraz obsługiwana we wszystkich głównych przeglądarkach oprócz Internet Explorera ( źródło ). .Array.from
że mutuje dane, nie zapewnia głębokiego kopiowania / głębokiego klonowania.Dla tablicy zawierającej obiekty ES6
źródło