Jak przekazać zmienne przez referencję w JavaScript? Mam 3 zmienne, dla których chcę wykonać kilka operacji, więc chcę umieścić je w pętli for i wykonać operacje na każdej z nich.
pseudo kod:
myArray = new Array(var1, var2, var3);
for (var x = 0; x < myArray.length; x++){
//do stuff to the array
makePretty(myArray[x]);
}
//now do stuff to the updated vars
Jak najlepiej to zrobić?
javascript
variables
pass-by-reference
BFTrick
źródło
źródło
makePretty(var1); makePretty(var2); makePretty(var3); ...
arr = [var1, var2, var3]; for (var i = 0, len = arr.length; i < len; i++) { arr[i] = makePretty(arr[i]); }
- po prostu musisz zapisać wartość zwróconą zmakePretty
powrotem w gnieździe w tablicy.Odpowiedzi:
W JavaScript nie ma opcji „pass by reference”. Możesz przekazać obiekt (co oznacza, że możesz przekazać wartość przez odwołanie do obiektu), a następnie funkcja może zmodyfikować zawartość obiektu:
Możesz iterować właściwości tablicy z indeksem numerycznym i modyfikować każdą komórkę tablicy, jeśli chcesz.
Należy zauważyć, że „podanie przez odniesienie” jest bardzo specyficznym terminem. Nie oznacza to po prostu, że można przekazać odwołanie do modyfikowalnego obiektu. Zamiast tego oznacza to, że możliwe jest przekazanie prostej zmiennej w taki sposób, aby umożliwić funkcji zmodyfikowanie tej wartości w kontekście wywołania . Więc:
W języku takim jak C ++ można to zrobić, ponieważ język ten działa (sortowanie) przechodzący przez odniesienie.
edytuj - to ostatnio (marzec 2015) ponownie wysadziło Reddita na blogu podobnym do mojego wspomnianego poniżej, choć w tym przypadku o Javie. Przyszło mi do głowy, czytając w komentarzach Reddita tam iz powrotem, że duża część zamieszania wynika z niefortunnej kolizji obejmującej słowo „odniesienie”. Terminologia „pass by reference” i „pass by value” poprzedza koncepcję posiadania „obiektów” do pracy w językach programowania. Tak naprawdę wcale nie chodzi o przedmioty; chodzi o parametry funkcji, a konkretnie o to, jak parametry funkcji są „podłączone” (lub nie) do środowiska wywołującego. W szczególności,i wyglądałby dokładnie tak, jak w JavaScript. Jednak można również .móc modyfikować odwołanie do obiektu w środowisku wywołującym, a to jest kluczowa rzecz, której nie można zrobić w JavaScript. Język pass-by-referencyjny nie przekazywałby samego odwołania, ale odniesienie do odwołania
edycja - tutaj jest post na blogu na ten temat. (Zwróć uwagę na komentarz do tego postu, który wyjaśnia, że C ++ tak naprawdę nie ma przekazu referencyjnego. To prawda. C ++ ma jednak możliwość tworzenia odwołań do zmiennych zwykłych, albo jawnie w punkcie funkcji wywołanie w celu utworzenia wskaźnika lub pośrednio podczas wywoływania funkcji, których podpis typu argumentu wymaga, aby to zrobić. Są to kluczowe rzeczy, których JavaScript nie obsługuje).
źródło
Tablice i obiekty są przekazywane przez odniesienie lub wartość na podstawie następujących warunków:
jeśli ustawiasz wartość obiektu lub tablicy, jest to Pass by Value.
object1 = {prop: "car"}; array1 = [1,2,3];
jeśli zmieniasz wartość właściwości obiektu lub tablicy, to jest to Pass by Reference.
object1.prop = "car"; array1[0] = 9;
Kod
źródło
Obejście problemu polegające na przekazywaniu zmiennej jak przez odwołanie:
EDYTOWAĆ
tak, właściwie możesz to zrobić bez dostępu do globalnego
źródło
Prosty przedmiot
Obiekt niestandardowy
Obiekt
rvar
Deklaracja zmienna
Lub:
Kod testowy
Wynik konsoli testowej
źródło
Jeszcze innym podejściem do przekazywania dowolnych (lokalnych, prymitywnych) zmiennych przez odniesienie jest zawijanie zmiennej zamykaniem „w locie” przez
eval
. Działa to również z „use strict”. (Uwaga: należy pamiętać, żeeval
nie jest przyjazny dla optymalizatorów JS, również brak cudzysłowów wokół nazwy zmiennej może powodować nieprzewidywalne wyniki)Próbka na żywo https://jsfiddle.net/t3k4403w/
źródło
W rzeczywistości jest całkiem niezłe rozwiązanie:
źródło
Osobiście nie podoba mi się funkcja „pass by reference” oferowana przez różne języki programowania. Być może dlatego, że właśnie odkrywam koncepcje programowania funkcjonalnego, ale zawsze dostaję gęsiej skórki, gdy widzę funkcje wywołujące skutki uboczne (takie jak manipulowanie parametrami przekazywanymi przez referencję). Osobiście zdecydowanie popieram zasadę „pojedynczej odpowiedzialności”.
IMHO, funkcja powinna zwrócić tylko jeden wynik / wartość za pomocą słowa kluczowego return. Zamiast modyfikować parametr / argument, po prostu zwrócę zmodyfikowaną wartość parametru / argumentu i pozostawiam wszelkie pożądane zmiany przypisania do kodu wywołującego.
Ale czasami (mam nadzieję, że bardzo rzadko) konieczne jest zwrócenie dwóch lub więcej wartości wyników z tej samej funkcji. W takim przypadku wolałbym uwzględnić wszystkie uzyskane wartości w jednej strukturze lub obiekcie. Ponownie przetwarzanie ponownych przypisań powinno zależeć od kodu wywołującego.
Przykład:
Załóżmy, że przekazywanie parametrów byłoby obsługiwane przy użyciu specjalnego słowa kluczowego, takiego jak „ref” na liście argumentów. Mój kod może wyglądać mniej więcej tak:
Zamiast tego wolałbym zrobić coś takiego:
Gdybym musiał napisać funkcję, która zwraca wiele wartości, nie używałbym również parametrów przekazywanych przez referencję. Chciałbym więc uniknąć takiego kodu:
Zamiast tego wolałbym zwrócić obie nowe wartości wewnątrz obiektu, takie jak to:
Te przykłady kodu są dość uproszczone, ale z grubsza pokazuje, jak osobiście poradziłbym sobie z takimi rzeczami. Pomaga mi utrzymać różne obowiązki we właściwym miejscu.
Szczęśliwego kodowania. :)
źródło
findStuff
po prostu zwrócić wynikową tablicę. Ty też musisz zadeklarowaćfoundArray
zmienną, więc chciałbym się bezpośrednio przypisać do niego wynikającej tablicę:var foundArray = findStuff(inArray); if (foundArray.length > 0) { /* process foundArray */ }
. To 1) sprawi, że kod wywołujący będzie bardziej czytelny / zrozumiały, oraz 2) znacznie uprości wewnętrzną funkcjonalność (a tym samym także testowalność)findStuff
metody, czyniąc ją znacznie bardziej elastyczną w różnych (ponownie) przypadkach użycia / scenariuszach.Bawiłem się składnią, aby robić takie rzeczy, ale wymaga to trochę pomocników, które są trochę niezwykłe. Zaczyna się w ogóle od nieużywania „var”, ale prostego pomocnika „DECLARE”, który tworzy zmienną lokalną i definiuje jej zakres poprzez anonimowe wywołanie zwrotne. Kontrolując sposób deklarowania zmiennych, możemy zawijać je w obiekty, aby zasadniczo zawsze mogły być przekazywane przez referencję. Jest to podobne do powyższej odpowiedzi Eduardo Cuomo, ale poniższe rozwiązanie nie wymaga użycia ciągów jako identyfikatorów zmiennych. Oto minimalny kod pokazujący tę koncepcję.
źródło
właściwie to jest naprawdę łatwe,
problemem jest zrozumienie, że po przekazaniu klasycznych argumentów można znaleźć się w innej strefie tylko do odczytu.
rozwiązaniem jest przekazywanie argumentów za pomocą obiektowego projektu JavaScript,
jest to to samo, co umieszczenie argumentów w zmiennej globalnej / o zasięgu, ale lepiej ...
możesz także obiecać coś, co pozwoli cieszyć się znanym łańcuchem: oto cała rzecz o strukturze przypominającej obietnicę
Lub jeszcze lepiej..
action.setArg(["empty-array"],"some string",0x100,"last argument").call()
źródło
this.arg
działa tylko zaction
instancją. To nie działa.JavaScript może modyfikować elementy tablicy wewnątrz funkcji (jest przekazywana jako odwołanie do obiektu / tablicy).
Oto inny przykład:
źródło
JS nie jest silnym typem, pozwala rozwiązywać problemy na wiele różnych sposobów, jak się wydaje w tym bieżniku.
Jednak z punktu widzenia łatwości konserwacji musiałbym się zgodzić z Bartem Hoflandem. Funkcja powinna uzyskać argumenty do zrobienia czegoś i zwrócić wynik. Dzięki temu łatwo można je ponownie wykorzystać.
Jeśli uważasz, że zmienne muszą być przekazywane przez referencję, możesz lepiej skorzystać z ich wbudowania w obiekty IMHO.
źródło
Odkładając na bok dyskusję na zasadzie odniesienia, ci, którzy wciąż szukają rozwiązania zadanego pytania, mogą użyć:
źródło
Wiem dokładnie, co masz na myśli. To samo w Swift nie będzie problemu. Najważniejsze jest
let
nie używaćvar
.Fakt, że prymitywy są przekazywane przez wartość, ale fakt, że wartość
var i
w punkcie iteracji nie jest kopiowana do funkcji anonimowej, jest co najmniej dość zaskakujący.źródło