Typy prymitywne (liczba, ciąg itp.) Są przekazywane przez wartość, ale obiekty są nieznane, ponieważ oba mogą być przekazywane przez wartość (w przypadku, gdy uważamy, że zmienna przechowująca obiekt jest w rzeczywistości odniesieniem do obiektu ) i przekazywany przez odniesienie (gdy weźmiemy pod uwagę, że zmienna obiektu zawiera sam obiekt).
Chociaż na koniec nie ma to tak naprawdę znaczenia, chcę wiedzieć, jak poprawnie przedstawiać argumenty omawiające konwencje. Czy istnieje fragment specyfikacji JavaScript, który określa, jaka powinna być semantyka w tym zakresie?
javascript
pass-by-reference
pass-by-value
Danail Nachev
źródło
źródło
var x=3, y=x; f(x); alert(y === x);
wówczas funkcjaf()
może zgłosić alert,false
a nietrue
. W JavaScript jest to niemożliwe, więc nie jest to odnośnik. Dobrze, że można przekazywać referencje do obiektów modyfikowalnych, ale nie to oznacza „przekazywać przez referencję”. Jak powiedziałem, szkoda, że terminologia jest tak myląca.Odpowiedzi:
To jest interesujące w JavaScript. Rozważ ten przykład:
To daje wynik:
obj1
ogóle nie było odniesieniem, zmianaobj1.item
nie miałaby wpływu naobj1
zewnętrzną stronę funkcji.num
byłby100
iobj2.item
czytałby"changed"
.Zamiast tego sytuacja jest taka, że przekazywany element jest przekazywany według wartości. Ale przedmiot przekazywany przez wartość sam w sobie jest odniesieniem. Technicznie jest to nazywane dzieleniem przez połączenie .
W praktyce oznacza to, że jeśli zmienisz sam parametr (jak w przypadku
num
iobj2
), nie wpłynie to na element, który został wprowadzony do parametru. Ale jeśli zmienisz WEWNĘTRZNE parametru, nastąpi propagacja z powrotem (jak w przypadkuobj1
).źródło
item
właściwość obiektu, do którego odwołuje się obiekt obj1, zmieniasz wartość właściwości elementu, która pierwotnie była ustawiona na „niezmieniona”. Kiedy przypisujesz obj2 wartości {item: "updated"} zmieniasz odniesienie do nowego obiektu (który natychmiast wychodzi poza zakres po wyjściu z funkcji). Staje się bardziej oczywiste, co się dzieje, jeśli nazwiesz funkcję params rzeczy takie jak numf, obj1f i obj2f. Potem widzisz, że parametry ukrywały zewnętrzne nazwy zmiennych.ref
słowa kluczowego.) Zwykle wystarczy, że funkcja zwróci nowy obiekt i zrobi przypisanie w punkcie, w którym wywołujesz funkcję. Np.foo = GetNewFoo();
ZamiastGetNewFoo(foo);
var obj1 = { item: 'unchanged' }; var obj2 = obj1; obj2.item = 'changed';
i obserwować taki sam efekt jak w twoim przykładzie. Dlatego osobiście odsyłam odpowiedź Tima GoodmanaZawsze przechodzi przez wartość, ale dla obiektów wartością zmiennej jest odwołanie. Z tego powodu, gdy mijasz obiekt i zmieniasz jego elementy , zmiany te pozostają poza funkcją. To sprawia, że wygląda jak przekazywany przez odniesienie. Ale jeśli faktycznie zmienisz wartość zmiennej obiektowej, zobaczysz, że zmiana nie utrzymuje się, co dowodzi, że naprawdę przechodzi ona przez wartość.
Przykład:
Wynik:
źródło
changeObject
zmieniłem,x
aby zawierał odwołanie do nowego obiektu. nawiasem mówiąc,x = {member:"bar"};
jest równoważne temu,x = new Object(); x.member = "bar";
co mówię, jest również prawdą w C #.ref
słowa kluczowego, możesz przekazać referencję przez referencję (zamiast domyślnego przekazywania referencji przez wartość), a następnie zmiana na wskazanie na anew Object()
będzie się utrzymywać .Zmienna nie „trzyma” obiektu; zawiera odniesienie. Możesz przypisać to odwołanie do innej zmiennej, a teraz oba odnoszą się do tego samego obiektu. Zawsze przechodzi przez wartość (nawet jeśli ta wartość jest odniesieniem ...).
Nie ma możliwości zmiany wartości przechowywanej przez zmienną przekazywaną jako parametr, co byłoby możliwe, gdyby JavaScript obsługiwał przekazywanie przez referencję.
źródło
Moje dwa centy ... Tak to rozumiem. (Możesz mnie poprawić, jeśli się mylę)
Czas wyrzucić wszystko, co wiesz o przekazywaniu według wartości / referencji.
Ponieważ w JavaScript nie ma znaczenia, czy jest przekazywany przez wartość, przez referencję czy cokolwiek innego. Liczy się mutacja vs. przypisanie parametrów przekazanych do funkcji.
OK, pozwól, że zrobię co w mojej mocy, aby wyjaśnić, co mam na myśli. Powiedzmy, że masz kilka obiektów.
To, co zrobiliśmy, to „przypisanie” ... Przypisaliśmy 2 oddzielne puste obiekty do zmiennych „object1” i „object2”.
Powiedzmy, że bardziej lubimy obiekt1 ... Więc „przypisujemy” nową zmienną.
Następnie, z jakiegokolwiek powodu, decydujemy, że obiekt 2 bardziej nam się podoba. Więc po prostu wykonujemy małe przeniesienie.
Nic się nie stało z obiektem1 lub obiektem2. Nie zmieniliśmy żadnych danych. Wszystko, co zrobiliśmy, to ponowne przypisanie tego, co jest naszym ulubionym przedmiotem. Ważne jest, aby wiedzieć, że zarówno obiekt2, jak i ulubiony obiekt są przypisane do tego samego obiektu. Możemy zmienić ten obiekt za pomocą jednej z tych zmiennych.
OK, teraz spójrzmy na prymitywy takie jak na przykład łańcuchy
Ponownie wybieramy ulubionego.
Zarówno nasze ulubione zmienne ciąg, jak i łańcuch1 są przypisane do „Hello world”. A co jeśli chcemy zmienić nasz ulubiony ciąg ??? Co się stanie???
Uh oh .... Co się stało. Nie mogliśmy zmienić string1, zmieniając ulubiony ciąg ... Dlaczego? Ponieważ nie zmieniliśmy naszego obiektu ciągu . Wszystko, co zrobiliśmy, to „RE ASSIGN” zmienna favoriteString do nowego ciągu. To zasadniczo odłączyło go od string1. W poprzednim przykładzie, kiedy zmieniliśmy nazwę naszego obiektu, nie przypisaliśmy niczego. (Cóż, nie do samej zmiennej ... jednak przypisaliśmy właściwość name do nowego ciągu.) Zamiast tego po prostu zmutowaliśmy obiekt, który utrzymuje połączenia między 2 zmiennymi a obiektami leżącymi u ich podstaw. (Nawet jeśli chcieliśmy zmodyfikować lub zmutować sam obiekt łańcuchowy, nie mogliśmy tego zrobić, ponieważ w JavaScript są ciągi niezmienne.)
Teraz do funkcji i przekazywania parametrów .... Kiedy wywołujesz funkcję i przekazujesz parametr, to, co zasadniczo robisz, to „przypisanie” do nowej zmiennej, i działa dokładnie tak samo, jakbyś po prostu przypisał za pomocą znak równości (=).
Weź te przykłady.
Teraz to samo, ale z funkcją
OK, teraz podajmy kilka przykładów z użyciem obiektów zamiast ... najpierw, bez funkcji.
Teraz to samo, ale z wywołaniem funkcji
OK, jeśli przeczytasz cały ten post, być może lepiej rozumiesz, jak wywołania funkcji działają w JavaScript. Nie ma znaczenia, czy coś jest przekazywane przez odniesienie, czy przez wartość ... Liczy się przypisanie vs mutacja.
Za każdym razem, gdy przekazujesz zmienną do funkcji, „przypisujesz” do dowolnej nazwy zmiennej parametru, tak jak w przypadku użycia znaku równości (=).
Zawsze pamiętaj, że znak równości (=) oznacza przypisanie. Zawsze pamiętaj, że przekazanie parametru do funkcji w JavaScript oznacza również przypisanie. Są takie same, a dwie zmienne są połączone dokładnie w ten sam sposób (to znaczy tak nie jest, chyba że policzysz, że są przypisane do tego samego obiektu).
Jedyny moment, w którym „modyfikowanie zmiennej” wpływa na inną zmienną, następuje po zmutowaniu obiektu leżącego u podstaw (w którym to przypadku nie zmodyfikowano zmiennej, ale sam obiekt.
Nie ma sensu wprowadzać rozróżnienia między obiektami a prymitywami, ponieważ działa on tak samo dokładnie, jakbyś nie miał funkcji, a jedynie użył znaku równości do przypisania nowej zmiennej.
Jedynym gotcha jest to, że nazwa zmiennej, którą przekazujesz do funkcji, jest taka sama jak nazwa parametru funkcji. Kiedy tak się dzieje, musisz traktować parametr wewnątrz funkcji tak, jakby była to zupełnie nowa zmienna prywatna dla funkcji (ponieważ tak jest)
źródło
foo(char *a){a="hello";}
nic nie robi, ale jeśli to zrobiszfoo(char *a){a[0]='h';a[1]='i';a[2]=0;}
, zostanie zmieniony na zewnątrz, ponieważa
jest to miejsce w pamięci przekazane przez wartość, która odwołuje się do łańcucha znaków (tablica znaków). Przekazywanie struktur (podobnych do obiektów js) przez wartość w C jest dozwolone, ale nie zalecane. JavaScript po prostu egzekwuje te najlepsze praktyki i ukrywa niepotrzebne i zwykle niepożądane cruft ... a na pewno ułatwia czytanie.source = { "id":"1"}; copy = source /*this is wrong*/; copy.id="2"
tego źródła nadal było {"id": "1"}?Rozważ następujące:
Więc
zapomnij o „przekaż przez referencję / wartość”, nie rozłączaj się przy „przekaż przez referencję / wartość”, ponieważ:Aby odpowiedzieć na twoje pytanie: wskaźniki są przekazywane.
Kilka uwag końcowych:
źródło
{'George', 1}
wartości, ale używam tylko jednej z nich na raz, to jak zarządza się innymi? A co się stanie, gdy przypiszę zmienną do wartości innej zmiennej? Czy następnie wskazuję wskaźnik, czy wskazuję wskazówkę właściwego operandu? Czyvar myExistingVar = {"blah", 42}; var obj = myExistingVar;
skutkujeobj
wskazaniem{"blah", 42}
lubmyExistingVar
?1)
uruchomiłem profil pamięci w narzędziach programistycznych przeglądarki dla funkcji pętli, takiej jak ta, którą opisałeś i zauważyłem gwałtowne zużycie pamięci podczas całego procesu zapętlania. Wydaje się to wskazywać, że w trakcie każdej iteracji pętli rzeczywiście powstają nowe identyczne obiekty. Gdy kolce nagle spadają, śmieciarz po prostu wyczyścił grupę tych nieużywanych obiektów.2)
Jeśli chodzi o coś takiegovar a = b
, javascript nie zapewnia mechanizmu używania wskaźników, więc zmienna nigdy nie może wskazywać na wskaźnik (jak w C), chociaż niewątpliwie korzysta z niego silnik javascript. Więc ...var a = b
wskażea
„na punkt właściwego operandu”Obiekt poza funkcją jest przekazywany do funkcji przez podanie odwołania do obiektu zewnętrznego.
Kiedy używasz tego odwołania do manipulowania jego obiektem, wpływa to na obiekt na zewnątrz. Jeśli jednak wewnątrz funkcji postanowiłeś wskazać odniesienie do czegoś innego, w ogóle nie wpłynąłeś na obiekt na zewnątrz, ponieważ wszystko, co zrobiłeś, to przekierowanie odniesienia do czegoś innego.
źródło
Pomyśl o tym w ten sposób: zawsze chodzi o wartość. Jednak wartością obiektu nie jest sam obiekt, ale odniesienie do tego obiektu.
Oto przykład, przekazując liczbę (prymitywny typ)
Powtórzenie tego z obiektem daje różne wyniki:
Jeszcze jeden przykład:
źródło
Bardzo szczegółowe wyjaśnienie na temat kopiowania, przekazywania i porównywania według wartości i przez odniesienie znajduje się w tym rozdziale książki „JavaScript: Przewodnik definitywny” .
źródło
JavaScript jest zawsze wartością przekazywaną ; wszystko ma wartość.
Obiekty są wartościami, a funkcje składowe obiektów same w sobie (pamiętaj, że funkcje są pierwszorzędnymi obiektami w JavaScript). Także w odniesieniu do koncepcji, że wszystko w JavaScript jest przedmiotem ; To jest źle. Ciągi, symbole, liczby, logiczne, null i niezdefiniowane są prymitywami .
Czasami mogą korzystać z niektórych funkcji członkowskich i właściwości odziedziczonych z ich podstawowych prototypów, ale jest to tylko dla wygody. Nie oznacza to, że same są obiektami. Wypróbuj następujące informacje:
W obu alertach znajdziesz wartość, która jest niezdefiniowana.
źródło
x = "teste"; x.foo = 12;
itd. To, że właściwość nie jest trwała, nie oznacza, że nie jest obiektem. Jak mówi MDN: w JavaScript prawie wszystko jest przedmiotem. Wszystkie typy pierwotne oprócz null i undefined są traktowane jak obiekty. Można im przypisać właściwości (przypisane właściwości niektórych typów nie są trwałe) i mają wszystkie cechy obiektów. linkW JavaScript typ wartości kontroluje wyłącznie , czy ta wartość zostanie przypisana przez kopiowanie wartości, czy kopiowanie referencyjne .
Wartości pierwotne są zawsze przypisywane / przekazywane przez kopiowanie wartości :
null
undefined
ES6
Wartości złożone są zawsze przypisywane / przekazywane przez kopię referencyjną
Na przykład
W powyższym fragmencie, ponieważ
2
jest prymitywem skalarnym,a
zawiera jedną początkową kopię tej wartości ib
przypisuje jej inną kopię. Zmieniającb
, w żaden sposób nie zmieniasz wartości wa
.Ale oba
c
id
są oddzielne odniesienia do tej samej wartości dzielonego[1,2,3]
, która jest wartością związek. Ważne jest, aby pamiętać, żec
anid
więcej, ani „nie posiada”[1,2,3]
wartości - oba są po prostu równymi odniesieniami do wartości. Tak więc, gdy używasz dowolnego odwołania do modyfikacji (.push(4)
) rzeczywistej wspólnejarray
wartości, wpływa to tylko na jedną wspólną wartość, a oba odwołania będą odnosić się do nowo zmodyfikowanej wartości[1,2,3,4]
.Kiedy wykonujemy to zadanie
b = [4,5,6]
, nie robimy absolutnie nic, aby wpłynąć naa
to, gdzie nadal odwołuje się ([1,2,3]
). Aby to zrobić,b
musiałby być wskaźnikiema
zamiast odniesienia doarray
- ale JS nie ma takiej możliwości!Kiedy przekazujemy argument
a
, przypisuje on kopięa
odwołania dox
.x
ia
są osobnymi odniesieniami wskazującymi tę samą[1,2,3]
wartość. Teraz wewnątrz funkcji możemy użyć tego odwołania do mutacji samej wartości (push(4)
). Ale kiedy dokonujemy przypisaniax = [4,5,6]
, nie ma to żadnego wpływu na to, gdziea
wskazuje początkowe odniesienie - nadal wskazuje na (teraz zmodyfikowaną)[1,2,3,4]
wartość.Aby skutecznie przekazać wartość złożoną (jak an
array
) przez kopiowanie wartości, musisz ręcznie wykonać jej kopię, aby przekazane odwołanie nadal nie wskazywało na oryginał. Na przykład:Wartość złożona (obiekt, tablica itp.), Którą można przekazać przez kopię referencyjną
Tutaj
obj
działa jako opakowanie dla pierwotnej właściwości skalarneja
. Po przekazaniufoo(..)
kopiaobj
referencji jest przekazywana i ustawiana nawrapper
parametr. Teraz możemy użyćwrapper
odwołania, aby uzyskać dostęp do współdzielonego obiektu i zaktualizować jego właściwość. Po zakończeniu funkcjiobj.a
zobaczy zaktualizowaną wartość42
.Źródło
źródło
cóż, chodzi o „wydajność” i „szybkość” oraz w prostym słowie „zarządzanie pamięcią” w języku programowania.
w javascript możemy umieścić wartości na dwóch warstwach: type1 -
objects
i type2 - wszystkie inne typy wartości, takie jakstring
&boolean
& etcjeśli wyobrażasz sobie pamięć jako kwadraty poniżej, w których w każdym z nich można zapisać tylko jedną wartość type2:
każda wartość type2 (zielona) to pojedynczy kwadrat, podczas gdy wartość type1 (niebieski) to ich grupa :
chodzi o to, że jeśli chcesz wskazać wartość typu 2, adres jest prosty, ale jeśli chcesz zrobić to samo dla wartości typu 1, co wcale nie jest łatwe! :
i w bardziej skomplikowanej historii:
więc referencje mogą nas uratować:
podczas gdy zielona strzałka jest tutaj typową zmienną, fioletowa jest zmienną obiektową, więc ponieważ zielona strzałka (typowa zmienna) ma tylko jedno zadanie (i oznacza typową wartość), nie musimy oddzielać jej wartości od przesuwamy więc zieloną strzałkę z wartością tego, gdziekolwiek się ona znajduje, we wszystkich zadaniach, funkcjach i tak dalej ...
ale nie możemy zrobić tego samego z fioletową strzałką, możemy chcieć przenieść tu komórkę „Johna” lub wiele innych rzeczy ... więc fioletowa strzała przylgnie do tego miejsca i tylko typowe przypisane do niej strzałki będą się poruszać ...
bardzo myląca jest sytuacja, w której nie możesz zrozumieć, jak zmienia się twoja zmienna, do której się odwołujemy, spójrzmy na bardzo dobry przykład:
źródło
To trochę więcej wyjaśnień dla przekazywania przez wartość i przekazywania przez referencję (JavaScript). W tej koncepcji mówią o przekazywaniu zmiennej przez referencję i przekazywaniu zmiennej przez referencję.
Przekaż według wartości (typ pierwotny)
Przekaż przez odniesienie (obiekty)
c
i wskazuje na pewną pamięć, powiedzmy (0x012).d
wskazuje tę samą lokalizację (0x012).Przypadek specjalny, przekazany przez odniesienie (obiekty)
źródło
c
jest ustawiona na kopię odwołania do nowego obiektu.W JavaScript, gdy przypisujesz obiekt do zmiennej, wartość przypisana do zmiennej jest odniesieniem do obiektu:
źródło
Semantyka!! Ustalenie konkretnych definicji z konieczności spowoduje, że niektóre odpowiedzi i komentarze będą niezgodne, ponieważ nie opisują tego samego, nawet przy użyciu tych samych słów i fraz, ale bardzo ważne jest, aby uniknąć zamieszania (szczególnie dla nowych programistów).
Przede wszystkim istnieje wiele poziomów abstrakcji, których nie wszyscy zdają się rozumieć. Nowi programiści, którzy nauczyli się języków 4. lub 5. generacji, mogą mieć trudności z koncentracją się na pojęciach znanych z asemblera lub programistami C, którzy nie są podzieleni na stopnie na wskaźniki na wskaźniki. Przekazywanie przez odniesienie nie oznacza po prostu możliwości zmiany obiektu, do którego istnieje odwołanie, za pomocą zmiennej parametru funkcji.
Zmienna : Połączona koncepcja symbolu, który odwołuje się do wartości w określonym miejscu w pamięci. Termin ten jest zwykle zbyt obciążony, aby można go było stosować w pojedynkę przy omawianiu szczegółów.
Symbol : Ciąg tekstowy używany w odniesieniu do zmiennej (tj. Nazwa zmiennej).
Wartość : poszczególne bity przechowywane w pamięci i do których odwołuje się symbol zmiennej.
Lokalizacja pamięci : gdzie przechowywana jest wartość zmiennej. (Sama lokalizacja jest reprezentowana przez liczbę oddzielną od wartości przechowywanej w lokalizacji).
Parametr funkcji : Zmienna zadeklarowana w definicji funkcji, używana do odwoływania się do zmiennych przekazywanych do funkcji.
Argument funkcji : Zmienna poza funkcją, która jest przekazywana do funkcji przez program wywołujący.
Zmienna obiektowa : Zmienna, której podstawową wartością bazową nie jest sam „obiekt”, a raczej jej wartość jest wskaźnikiem (wartością lokalizacji pamięci) do innej lokalizacji w pamięci, w której przechowywane są rzeczywiste dane obiektu. W większości języków wyższej generacji aspekt „wskaźnika” jest skutecznie ukryty przez automatyczne usuwanie odnośników w różnych kontekstach.
Zmienna pierwotna : Zmienna, której wartość JEST wartością rzeczywistą. Nawet ta koncepcja może być skomplikowana przez automatyczne boxowanie i konteksty obiektowe różnych języków, ale ogólne idee są takie, że wartość zmiennej JEST rzeczywistą wartością reprezentowaną przez symbol zmiennej, a nie wskaźnik do innej lokalizacji pamięci.
Argumenty funkcji i parametry to nie to samo. Ponadto wartość zmiennej nie jest przedmiotem zmiennej (jak już zauważyli różni ludzie, ale najwyraźniej zostały zignorowane). Te rozróżnienia mają kluczowe znaczenie dla właściwego zrozumienia.
Przekazywanie według wartości lub Call-by-sharing (dla obiektów): Wartość argumentu funkcji jest KOPIOWANA do innej lokalizacji w pamięci, do której odwołuje się symbol parametru funkcji (niezależnie od tego, czy znajduje się na stosie, czy na stosie). Innymi słowy, parametr funkcji otrzymał kopię wartości przekazanego argumentu ... ORAZ (krytyczny) wartość argumentu NIE JEST NIGDY AKTUALIZOWANA / ZMIENIONA / ZMIENIONA przez funkcję wywołującą. Pamiętaj, że wartość zmiennej obiektowej NIE jest samym obiektem, a raczej wskaźnikiem do obiektu, więc przekazanie zmiennej obiektowej przez wartość kopiuje wskaźnik do zmiennej parametru funkcji. Wartość parametru funkcji wskazuje dokładnie ten sam obiekt w pamięci. Same dane obiektowe można zmienić bezpośrednio za pomocą parametru funkcji, ALE wartość argumentu funkcji NIE JEST NIGDY AKTUALIZOWANA, więc nadal będzie wskazywać na to samoobiekt w trakcie, a nawet po wywołaniu funkcji (nawet jeśli dane jego obiektu zostały zmienione lub jeśli parametrowi funkcji przypisano zupełnie inny obiekt). Błędne jest stwierdzenie, że argument funkcji został przekazany przez referencję tylko dlatego, że obiekt, do którego istnieje odwołanie, można aktualizować za pomocą zmiennej parametru funkcji.
Wywołanie / przekazanie przez odniesienie : Wartość argumentu funkcji może / zostanie zaktualizowana bezpośrednio przez odpowiedni parametr funkcji. Jeśli to pomaga, parametr funkcji staje się efektywnym „aliasem” argumentu - efektywnie odnoszą się do tej samej wartości w tym samym miejscu w pamięci. Jeśli argument funkcji jest zmienną obiektu, możliwość zmiany danych obiektu nie różni się od przypadku przekazywania wartości, ponieważ parametr funkcji nadal wskazuje ten sam obiekt co argument. Ale w przypadku zmiennej obiektowej, jeśli parametr funkcji jest ustawiony na zupełnie inny obiekt, wówczas argument również będzie wskazywał na inny obiekt - nie dzieje się tak w przypadku przekazywania wartości.
JavaScript nie przechodzi przez odniesienie. Jeśli będziesz czytał uważnie, zdasz sobie sprawę, że wszystkie przeciwne opinie błędnie rozumieją, co rozumie się przez wartość przekazywaną, i fałszywie wyciągają wniosek, że możliwość aktualizacji danych obiektu za pomocą parametru funkcji jest synonimem „przekazywanej przez wartość”.
Klonowanie / kopiowanie obiektu: tworzony jest nowy obiekt, a dane oryginalnego obiektu są kopiowane. Może to być kopia głęboka lub płytka, ale chodzi o to, że tworzony jest nowy obiekt. Tworzenie kopii obiektu jest odrębnym pojęciem od wartości przekazywanej. Niektóre języki rozróżniają obiekt klasy i struktury (lub tym podobne) i mogą mieć różne zachowanie do przekazywania zmiennych różnych typów. Ale JavaScript nie robi nic takiego automatycznie podczas przekazywania zmiennych obiektowych. Ale brak automatycznego klonowania obiektów nie przekłada się na przekazywanie przez odniesienie.
źródło
JavaScript przekazuje typy pierwotne według wartości, a typy obiektów przez referencję
- Brian Bi - Jakie języki programowania są przekazywane przez odniesienie?
Aktualizacja
Oto odpowiedź na to:
W JavaScript nie ma opcji „pass by reference”.
źródło
Mój prosty sposób na zrozumienie tego ...
Podczas wywoływania funkcji przekazujesz zawartość (odwołanie lub wartość) zmiennych argumentu, a nie same zmienne.
Wewnątrz funkcji, zmienne parametrów
inVar1
iinVar2
, odbieramy przekazywaną treść.Po
inVar2
otrzymaniu odwołania do{ prop: 2 }
możesz zmienić wartość właściwości obiektu.źródło
Przekazywanie argumentów do funkcji w JavaScript jest analogiczne do przekazywania parametrów przez wartość wskaźnika w C:
źródło
W przypadku prawników zajmujących się językiem programowania przejrzałem następujące sekcje ECMAScript 5.1 (który jest łatwiejszy do odczytania niż najnowsze wydanie) i posunąłem się do pytania na liście mailingowej ECMAScript.
TL; DR : Wszystkie rzeczy są przekazywane przez wartość, ale właściwości Objects są referencjami, a definicja obiektu jest przerażająco brakuje w standardzie.
Konstrukcja list argumentów
Sekcja 11.2.4 „Listy argumentów” mówi o tworzeniu listy argumentów składającej się tylko z 1 argumentu:
W tej sekcji wymieniono również przypadki, w których lista argumentów zawiera 0 lub> 1 argumentów.
Zatem wszystko jest przekazywane przez odniesienie.
Dostęp do właściwości obiektu
Sekcja 11.2.1 „Akcesorium nieruchomości”
Zatem właściwości obiektów są zawsze dostępne jako odniesienie.
W sprawie odniesienia
W sekcji 8.7 „Typ specyfikacji odniesienia” opisano, że odwołania nie są prawdziwymi typami w języku - służą jedynie do opisania zachowania operatorów usuwania, typeof i przypisania.
Definicja „obiektu”
W wydaniu 5.1 zdefiniowano, że „Obiekt jest zbiorem właściwości”. Dlatego możemy wnioskować, że wartością obiektu jest kolekcja, ale co do wartości kolekcji jest źle zdefiniowane w specyfikacji i wymaga trochę wysiłku, aby zrozumieć.
źródło
Dokumenty MDN wyjaśniają to jasno, nie będąc zbyt gadatliwym:
Źródło: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions#Description
źródło
W języku niskiego poziomu, jeśli chcesz przekazać zmienną przez referencję, musisz użyć określonej składni przy tworzeniu funkcji:
&age
Jest odniesieniem domyAge
, ale jeśli chcesz, wartość trzeba konwertować odniesienia, używając*age
.Javascript jest językiem wysokiego poziomu, który wykonuje tę konwersję za Ciebie. Tak więc, chociaż obiekty są przekazywane przez referencję, język konwertuje parametr referencyjny na wartość. Nie musisz używać
&
definicji funkcji, aby przekazać ją przez odwołanie, ani*
w ciele funkcji, aby przekonwertować odwołanie na wartość, JS robi to za Ciebie.Właśnie dlatego, gdy próbujesz zmienić obiekt wewnątrz funkcji, zastępując jego wartość (tj.
age = {value:5}
), Zmiana nie jest utrzymywana, ale jeśli zmienisz jej właściwości (tj.age.value = 5
), Tak się stanie.Ucz się więcej
źródło
Przeczytałem te odpowiedzi wiele razy, ale NAPRAWDĘ nie dostałem, dopóki nie dowiedziałem się o technicznej definicji „Dzwoń przez udostępnianie”, jak to określiła Barbara Liskov
Oznacza to, że odniesienia parametrów można zmieniać, jeśli przejdziesz i uzyskasz dostęp do samej wartości parametru. Z drugiej strony przypisanie do parametru zniknie po analizie i będzie niedostępne dla funkcji wywołującej.
źródło
Przeważnie najprostszy sposób
źródło
JSON.parse( JSON.stringify( obj ) )
to okropny sposób na głębokie klonowanie obiektów. Jest nie tylko powolny, ale może również powodować utratę danych.Znalazłem sposób przedłużyć z biblioteki underscore.js bardzo przydatna, gdy chcę przejść do obiektu jako parametr, który może być albo całkowicie zmodyfikowany lub zastąpiony.
źródło
Najbardziej zwięzłe wyjaśnienie, jakie znalazłem, to przewodnik po stylu AirBNB :
Prymitywy : kiedy uzyskujesz dostęp do typu prymitywnego, pracujesz bezpośrednio nad jego wartością
Na przykład:
Złożony : Gdy uzyskujesz dostęp do typu złożonego, pracujesz nad odniesieniem do jego wartości
Na przykład:
Tj. Typy pierwotne są przekazywane przez wartość, a typy złożone są przekazywane przez odwołanie.
źródło
Powiedziałbym, że jest to kopia po kopii -
Weź pod uwagę, że argumenty i obiekty zmienne są obiektami utworzonymi w kontekście wykonania utworzonym na początku wywołania funkcji - a twoja rzeczywista wartość / referencja przekazana do funkcji jest po prostu przechowywana w tych argumentach + obiektach zmiennych.
Mówiąc najprościej, dla typów pierwotnych wartości są kopiowane na początku wywołania funkcji, dla typu obiektu kopiowane są referencje.
źródło
Trwa dyskusja na temat użycia terminu „pass by reference” w JavaScript tutaj , ale aby odpowiedzieć na twoje pytanie:
(Z artykułu wspomnianego powyżej.)
źródło
Łatwym sposobem ustalenia, czy coś jest „przekazywane przez referencję”, jest to, czy można napisać funkcję „zamiany”. Na przykład w C możesz wykonać:
Jeśli nie możesz zrobić tego w JavaScript, to nie jest to „pass by reference”.
źródło
Tablica i obiekt są przekazywane jako referencja lub wartość w oparciu o te dwa warunki.
jeśli zmieniasz wartość tego obiektu lub tablicy za pomocą nowego obiektu lub tablicy, to jest ona przekazywana przez wartość.
object1 = {item: "car"}; array1=[1,2,3];
tutaj przypisujesz nowy obiekt lub tablicę do starego. nie zmieniasz wartości właściwości starego obiektu. więc jest przekazywana przez wartość.
jeśli zmieniasz wartość właściwości obiektu lub tablicy, jest ona przekazywana przez odwołanie.
object1.key1= "car"; array1[0]=9;
tutaj zmieniasz wartość właściwości starego obiektu. nie przypisujesz nowego obiektu ani tablicy do starego. więc jest przekazywany przez referencję.
Kod
źródło
źródło
Proste wartości w funkcjach nie zmienią tych wartości poza funkcją (są przekazywane przez wartość), podczas gdy wartości złożone - (są przekazywane przez odwołanie).
źródło