Mam zmienną, której wartością jest obiekt JSON. Bezpośrednio przypisuję tę zmienną do innej zmiennej, aby miały tę samą wartość. Tak to działa:
var a = $('#some_hidden_var').val(),
b = a;
To działa i oba mają tę samą wartość. Używam programu mousemove
obsługi zdarzeń do aktualizacji b
za pośrednictwem mojej aplikacji. Po kliknięciu przycisku chcę przywrócić b
pierwotną wartość, czyli wartość przechowywaną w a
.
$('#revert').on('click', function(e){
b = a;
});
Następnie, jeśli używam tego samego programu mousemove
obsługi zdarzeń, aktualizuje on oba, a
a b
wcześniej aktualizował tylko b
zgodnie z oczekiwaniami.
Jestem zaskoczony tym problemem! Co tu jest nie tak?
javascript
jquery
Rutwick Gangurde
źródło
źródło
a
został ustawiony z.val()
, zakładam, że jest to JSON (ciąg znaków), a nie obiekt - czy to prawda? Czy używaszJSON.parse(a)
kiedyś, aby uzyskać rzeczywisty obiekt?$.parseJSON
do konwersji na obiekt. Struktura:{ 'key': {...}, 'key': {...}, ...}
. Przepraszamy, nie mogę tutaj umieścić żadnego kodu, niedozwolone w moim miejscu pracy!a
jest obiekt?a
zmienną globalną?$.parseJSON()
bierze?), Trudno powiedzieć, na czym polega problem. Jeśli chodzi o zasady dotyczące miejsca pracy, nie musisz publikować całego rzeczywistego kodu, po prostu wymyśl krótszy i bardziej ogólny przykład, który demonstruje problem (i najlepiej, aby zawierał link do demonstracji na żywo na jsfiddle.net ) .Odpowiedzi:
Ważne jest, aby zrozumieć, co robi
=
operator w JavaScript, a czego nie.=
Operator nie robi kopii danych.=
Operator tworzy nowe odniesienie do samego danych.Po uruchomieniu oryginalnego kodu:
a
ib
są teraz dwiema różnymi nazwami dla tego samego obiektu .Wszelkie zmiany wprowadzone w zawartości tego obiektu będą widoczne identycznie, niezależnie od tego, czy odwołujesz się do niego za pośrednictwem
a
zmiennej, czyb
zmiennej. To ten sam obiekt.Tak więc, gdy później spróbujesz „przywrócić”
b
oryginalnya
obiekt za pomocą tego kodu:Kod właściwie nic nie robi , ponieważ
a
ib
są dokładnie tym samym. Kod jest taki sam, jak gdybyś napisał:co oczywiście nic nie da.
Dlaczego twój nowy kod działa?
Tutaj tworzysz zupełnie nowy obiekt z
{...}
literałem obiektu. Ten nowy obiekt nie jest tym samym, co stary obiekt. Więc teraz ustawiaszb
jako odniesienie do tego nowego obiektu, który robi to, co chcesz.Aby obsłużyć dowolny obiekt, możesz użyć funkcji klonowania obiektu, takiej jak ta wymieniona w odpowiedzi Armanda, lub ponieważ używasz jQuery, po prostu użyj tej
$.extend()
funkcji . Ta funkcja utworzy płytką kopię lub głęboką kopię obiektu. (Nie myl tego z$().clone()
metodą kopiowania elementów DOM, a nie obiektów).W przypadku płytkiej kopii:
Lub głęboka kopia:
Jaka jest różnica między płytką kopią a głęboką kopią? Płytka kopia jest podobna do kodu, który tworzy nowy obiekt z literałem obiektu. Tworzy nowy obiekt najwyższego poziomu zawierający odniesienia do tych samych właściwości, co oryginalny obiekt.
Jeśli twój obiekt zawiera tylko prymitywne typy, takie jak liczby i łańcuchy, głęboka kopia i płytka kopia zrobią dokładnie to samo. Ale jeśli twój obiekt zawiera inne obiekty lub tablice zagnieżdżone w nim, to płytka kopia nie kopiuje tych zagnieżdżonych obiektów, a jedynie tworzy do nich odniesienia. Więc możesz mieć ten sam problem z zagnieżdżonymi obiektami, który miałeś z obiektem najwyższego poziomu. Na przykład biorąc pod uwagę ten obiekt:
Jeśli zrobisz płytką kopię tego obiektu, wówczas
x
właściwość nowego obiektu będzie taka samax
jak oryginalnego:Teraz twoje obiekty będą wyglądać tak:
Możesz tego uniknąć dzięki głębokiej kopii. Głęboka kopia powtarza się do każdego zagnieżdżonego obiektu i tablicy (oraz daty w kodzie Armanda), aby utworzyć kopie tych obiektów w ten sam sposób, w jaki utworzyła kopię obiektu najwyższego poziomu. Więc zmiana
copy.x.y
nie wpłynieobj.x.y
.Krótka odpowiedź: w razie wątpliwości prawdopodobnie potrzebujesz głębokiej kopii.
źródło
$.extend()
funkcji. Szczegóły powyżej. :-)Odkryłem, że używanie JSON działa, ale uważaj na nasze odwołania cykliczne
źródło
let a = {}; let b = {a:a}; a.b = b; JSON.stringify(a)
da TypeErrorpytanie zostało już rozwiązane od dłuższego czasu, ale w przyszłości możliwe jest rozwiązanie
Uważaj, to działa poprawnie tylko wtedy, gdy a jest niezagnieżdżoną tablicą liczb i ciągów
źródło
newVariable = originalVariable.valueOf();
dla przedmiotów, których możesz użyć,
b = Object.assign({},a);
źródło
Powód jest prosty. JavaScript używa referencji, więc kiedy przypisujesz
b = a
, przypisujesz odwołanie,b
więc podczas aktualizacjia
również aktualizujeszb
Znalazłem to na stackoverflow i pomogę zapobiec takim sytuacjom w przyszłości, po prostu wywołując tę metodę, jeśli chcesz wykonać głęboką kopię obiektu.
źródło
if (obj instanceof x) { ... }
być inaczej, jeśli tylko pierwszy ?Nie rozumiem, dlaczego odpowiedzi są tak złożone. W Javascript prymitywy (łańcuchy, liczby itp.) Są przekazywane przez wartość i kopiowane. Obiekty, w tym tablice, są przekazywane przez odwołanie. W każdym razie przypisanie nowej wartości lub odniesienia do obiektu do „a” nie zmieni „b”. Ale zmiana zawartości „a” zmieni zawartość „b”.
Wklej dowolną z powyższych linii (pojedynczo) do węzła lub dowolnej konsoli javascript przeglądarki. Następnie wpisz dowolną zmienną, a konsola pokaże jej wartość.
źródło
W przypadku ciągów lub wartości wejściowych możesz po prostu użyć tego:
źródło
Większość odpowiedzi tutaj wykorzystuje wbudowane metody lub biblioteki / frameworki. Ta prosta metoda powinna działać dobrze:
źródło
Object.assign({},a)
Na razie sam to rozwiązałem. Oryginalna wartość ma tylko 2 właściwości podrzędne. Zreformowałem nowy obiekt z właściwościami od,
a
a następnie przypisałem go dob
. Teraz mój program obsługi zdarzeń aktualizuje się tylkob
, a mój oryginała
pozostaje taki, jaki jest.To działa dobrze. Nie zmieniłem ani jednej linii w moim kodzie poza powyższym i działa tak, jak chciałem. Więc zaufaj mi, nic innego się nie aktualizowało
a
.źródło
Rozwiązanie dla AngularJS :
źródło