... gdzie każdy obiekt ma również odniesienia do innych obiektów w tej samej tablicy?
Kiedy po raz pierwszy wpadłem na ten problem, pomyślałem o czymś takim
var clonedNodesArray = nodesArray.clone()
istniałby i szukał informacji na temat klonowania obiektów w javascript. Znalazłem pytanie na StackOverflow (odpowiedział ten sam @JohnResig) i wskazał, że z jQuery możesz zrobić
var clonedNodesArray = jQuery.extend({}, nodesArray);
sklonować obiekt. Próbowałem tego jednak, to tylko kopiuje odwołania do obiektów w tablicy. Więc jeśli ja
nodesArray[0].value = "red"
clonedNodesArray[0].value = "green"
wartości zarówno nodesArray [0], jak i clonedNodesArray [0] okażą się „zielone”. Potem spróbowałem
var clonedNodesArray = jQuery.extend(true, {}, nodesArray);
który głęboko kopiuje obiekt, ale dostałem komunikaty o „ zbyt dużej rekurencji ” i „ przepełnieniu stosu kontrolnego ” odpowiednio od Firebug i Opera Dragonfly.
Jak byś to zrobił? Czy to coś, czego nawet nie należy robić? Czy istnieje sposób wielokrotnego użytku w JavaScript?
źródło
Tak długo, jak obiekty zawierają treści serializowane przez JSON (bez funkcji, nie
Number.POSITIVE_INFINITY
itp.), Nie ma potrzeby, aby pętle klonowały tablice lub obiekty. Oto jedno-liniowe rozwiązanie czysto waniliowe.Podsumowując poniższe komentarze, podstawową zaletą tego podejścia jest to, że klonuje również zawartość tablicy, a nie tylko samą tablicę. Podstawowymi wadami jest ograniczenie pracy tylko nad treściami serializowanymi w JSON i jego wydajność (która jest znacznie gorsza niż
slice
podejście oparte na podejściu).źródło
null
iundefined
będą to problemy, ponieważ JSON ich nie obsługuje). Co więcej, jest to znacznie mniej wydajna operacja niżold_array.slice(0);
, która powinna działać zarówno lepiej, jak i szybciej.Rozwiązałem klonowanie tablicy obiektów za pomocą Object.assign
lub nawet krótszy ze składnią rozprzestrzeniania
źródło
{}
gonew Dinosaur()
.Jeśli wszystko, czego potrzebujesz, to płytka kopia, naprawdę łatwym sposobem jest:
źródło
0
, ale i tak możesz zadzwonić.slice()
przynajmniej w chromieslice
będzie nową tablicą, ale będzie zawierać odniesienia do oryginalnych obiektów tablicy.Najlepszy i najbardziej aktualny sposób wykonania tego klonu jest następujący:
Korzystanie z
...
operatora rozprzestrzeniania ES6.Oto najprostszy przykład:
W ten sposób rozkładamy tablicę na poszczególne wartości i umieszczamy ją w nowej tablicy za pomocą operatora [].
Oto dłuższy przykład pokazujący różne sposoby jego działania:
źródło
To działa dla mnie:
A jeśli potrzebujesz głębokiej kopii obiektów w tablicy:
źródło
źródło
JSON.parse(JSON.stringify(origArray));
JSON.parse(JSON.stringify(origArray));
jest zdecydowanie najprostszym rozwiązaniem.Mapa utworzy nową tablicę ze starego (bez odniesienia do starej), a wewnątrz mapy utworzysz nowy obiekt i przejdziesz przez właściwości (klucze) i przypiszesz wartości ze starego obiektu Array do odpowiednich właściwości do nowego obiektu.
Spowoduje to utworzenie dokładnie tej samej tablicy obiektów.
źródło
Mogę mieć prosty sposób na zrobienie tego bez konieczności bolesnej rekurencji i nie znając wszystkich drobniejszych szczegółów przedmiotowego obiektu. Korzystając z jQuery, po prostu przekonwertuj swój obiekt na JSON za pomocą jQuery
$.toJSON(myObjectArray)
, a następnie weź łańcuch JSON i oceń go z powrotem na obiekt. BAM! Gotowe i gotowe! Problem rozwiązany. :)źródło
eval
.eval()
w ogóle. To ryzyko bezpieczeństwa.Odpowiadam na to pytanie, ponieważ wydaje się, że nie istnieje proste i jednoznaczne rozwiązanie problemu „klonowania tablicy obiektów w JavaScript”:
To rozwiązanie iteruje wartości tablic, a następnie iteruje klucze obiektów, zapisując je do nowego obiektu, a następnie wypychając ten nowy obiekt do nowej tablicy.
Zobacz jsfiddle . Uwaga: proste
.slice()
lub[].concat()
niewystarczające dla obiektów w tablicy.źródło
Rozszerzenie JQuery działa dobrze, wystarczy określić, że klonujesz tablicę zamiast obiektu ( zwróć uwagę na [] zamiast {} jako parametr metody ext ):
źródło
Ta metoda jest bardzo prosta i możesz modyfikować swój klon bez modyfikowania oryginalnej tablicy.
źródło
[...oldArray]
ioldArray.slice(0)
zrobić płytkim skopiować jeden głębokim poziomie. Jest to więc bardzo przydatne, ale nie rzeczywisty pełny głęboki klon.lodash.clonedeep
npmJak wspomniał Daniel Lew, wykresy cykliczne mają pewne problemy. Gdybym miał ten problem, dodałbym specjalne
clone()
metody do problematycznych obiektów lub pamiętam, które obiekty już skopiowałem.Zrobiłbym to ze zmienną,
copyCount
która zwiększa się o 1 za każdym razem, gdy kopiujesz swój kod. Obiekt, który ma niższycopyCount
niż bieżący proces kopiowania, jest kopiowany. Jeśli nie, należy powołać się na kopię, która już istnieje. Dlatego konieczne jest połączenie z oryginału do jego kopii.Nadal jest jeden problem: pamięć. Jeśli masz to odniesienie od jednego obiektu do drugiego, prawdopodobnie przeglądarka nie może zwolnić tych obiektów, ponieważ zawsze są one skądś odwoływane. Będziesz musiał wykonać drugie przejście, w którym ustawisz wszystkie odwołania do kopii na Null. (Jeśli to zrobisz, nie będziesz musiał mieć
copyCount
logicznej, ale wystarczy booleanisCopied
, ponieważ możesz zresetować wartość w drugim przebiegu).źródło
Tablicy.slice można użyć do skopiowania tablicy lub jej części. Http://www.devguru.com/Technologies/Ecmascript/Quickref/Slice.html To działałoby z ciągami i liczbami. - zmiana ciągu w jedna tablica nie wpłynie na drugą - ale obiekty są nadal tylko kopiowane przez referencję, więc zmiany w obiektach referencyjnych w jednej tablicy miałyby wpływ na drugą tablicę.
Oto przykład menedżera cofania JavaScript, który może być przydatny w tym przypadku: http://www.ridgway.co.za/archive/2007/11/07/simple-javascript-undo-manager-for-dtos.aspx
źródło
Moje podejście:
daje mi ładny, czysty, głęboki klon oryginalnej tablicy - żaden obiekt nie odwołuje się do oryginału :-)
źródło
lodash ma
cloneDeep
do tego celu funkcję:źródło
Jeśli chcesz wdrożyć głęboki klon, użyj JSON.parse (JSON.stringify (twój {} lub []))
źródło
zapomnij eval () (jest najczęściej wykorzystywaną funkcją JS i powoduje spowolnienie kodu) i slice (0) (działa tylko dla prostych typów danych)
To dla mnie najlepsze rozwiązanie:
źródło
Byłem bardzo sfrustrowany tym problemem. Najwyraźniej problem powstaje, gdy wyślesz ogólną tablicę do metody $ .extend. Tak więc, aby to naprawić, dodałem mały czek i działa idealnie z tablicami ogólnymi, tablicami jQuery i dowolnymi obiektami.
Wywołaj używając:
źródło
To głęboko kopiuje tablice, obiekty, wartości zerowe i inne wartości skalarne, a także głęboko kopiuje wszelkie właściwości funkcji nienatywnych (co jest dość rzadkie, ale możliwe). (W celu zwiększenia wydajności nie próbujemy kopiować właściwości nienumerycznych do tablic).
źródło
Korzystam z nowej metody ECMAScript 6 Object.assign :
pierwszym argumentem tej metody jest tablica do aktualizacji, przekazujemy pusty obiekt, ponieważ chcemy mieć nowy obiekt.
możemy również użyć tej składni, która jest taka sama, ale krótsza:
źródło
Możemy wynaleźć prostą metodę macierzy rekurencyjnej do klonowania tablic wielowymiarowych. Podczas gdy obiekty w zagnieżdżonych tablicach zachowują odniesienie do odpowiednich obiektów w tablicy źródłowej, tablice tego nie zrobią.
źródło
W JavaScript, tablica i kopia obiektu zmieniają wartości początkowe, więc rozwiązaniem jest kopiowanie głębokie.
Głęboka kopia oznacza tworzenie nowej tablicy i kopiowanie wartości, ponieważ cokolwiek się z nią stanie, nigdy nie wpłynie na pierwotną.
JSON.parse
iJSON.stringify
jest najlepszym i prostym sposobem na głębokie kopiowanie.JSON.stringify()
Metoda konwertuje wartość JavaScript do JSON string.TheJSON.parse()
metody analizuje ciąg JSON, konstruowanie wartości JavaScript lub obiekt opisany przez ciąg.// Deep Clone
Aby uzyskać więcej informacji: Przeczytaj tutaj
źródło
z jQuery:
źródło
Poniższy kod wykona rekurencyjnie głębokie kopiowanie obiektów i tablicy :
Źródło
źródło
arguments.callee
nie jest dostępny w trybie ścisłym i w przeciwnym razie ma problemy z wydajnością.Kilka eleganckich sposobów głębokiego klonowania w javascript
https://mootools.net/core/docs/1.6.0/Types/Object
https://scotch.io/bar-talk/copying-objects-in-javascript
1) Waniliowa metoda Javascript do klonowania obiektów
2) Sprytne wykorzystanie biblioteki JSON do głębokiego klonowania obiektów
3) Korzystanie z funkcji $ .extend () jQuery
4) Używanie funkcji klonowania () Mootools do klonowania obiektów
źródło
Wydaje mi się, że udało mi się napisać ogólną metodę głębokiego klonowania dowolnej struktury JavaScript, która głównie
Object.create
jest obsługiwana we wszystkich nowoczesnych przeglądarkach. Kod jest taki:źródło
Object.create
będzie traktowanyitem
jako prototyp obiektu, ale różni się od klonowania. Jeśliitem
zostanie zmodyfikowany, zmiany zostaną odzwierciedlone w jego „klonie” i odwrotnie. To podejście nie działa.Również do klonowania obiektów zamierzałem po prostu zasugerować ECMAScript 6
reduce()
:Ale szczerze, jeszcze bardziej podoba mi się odpowiedź @dinodsaurus. Po prostu umieszczam tę wersję tutaj jako inną opcję, ale osobiście będę jej używać
map()
zgodnie z sugestią @dinodsaurus.źródło
W zależności od tego, czy masz podkreślnik, czy Babel, jest to Benchmark innego sposobu głębokiego klonowania tablicy.
https://jsperf.com/object-rest-spread-vs-clone/2
Wygląda na to, że babel jest najszybszy.
źródło
źródło