Używamy instrukcji return opcjonalnie w funkcjach JavaScript. To słowo kluczowe. Ale jaki jest rzeczywisty typ return
siebie. Właściwie zdezorientowałem się, widząc przykład:
function add(a, b) {
return (
console.log(a + b),
console.log(arguments)
);
}
add(2, 2);
Wynik:
4
[2, 2]
Możemy więc przekazać do return
instrukcji wyrażenia oddzielone przecinkami . Czy to jest funkcja?
A zaczynając od tego, czy możemy zgadnąć, że każde słowo kluczowe w JavaScript jest ostatecznie funkcją?
Napisałem mały blog jako sedno tej dyskusji. Możesz to sprawdzić tutaj .
javascript
return
keyword
Arnab Das
źródło
źródło
var a = (2 + 2)
.var a = (1, 2)
- spowoduje to, że otrzymamya
wartość2
ze względu na sposób działania operatora przecinka (tak, przecinek jest operatorem matematycznym, takim jak+
lub|
itp., A konkretnie w rachunku lambada operator przecinka implementuje kombinator K)Odpowiedzi:
Nie ma typu, nie jest wartością.
Próba
typeof return;
da ciUnexpected token return
.Nie, chociaż nawiasy mogą służyć do wywoływania funkcji, tutaj są one operatorem grupowania zawierającym kilka wyrażeń oddzielonych przecinkiem .
Bardziej użyteczną demonstracją byłoby:
Który wyprowadza,
0
ponieważ wynika + b
jest ignorowany (znajduje się po lewej stronie operatora przecinka) ia - b
jest zwracany.źródło
return
nie widzą ich, o co prosiłeś .a + b
po prostu nie ma widocznego efektu, ponieważ nie ma skutków ubocznych, a wartość jest odrzucana (cóż, biorąc pod uwagę, że nie ma praktycznego efektu, możliwe jest, że optymalizujący kompilator może ją usunąć, ale nie ma to praktycznej różnicy).if
), jest ocena zwarcia. Operator przecinka nie powoduje zwarcia, więc obliczy obie strony. Wtedy zwróci ostatni. Jest to wyraźnie celem operatora przecinka, aby zgrupować wyrażenia w jednej instrukcji (zwykle wynikowa wartość całej instrukcji jest ignorowana), najczęściej używany do inicjalizacji zmiennej:var i = 2, j = 3, k = 4;
Jestem trochę zszokowany, że nikt tutaj nie odniósł się bezpośrednio do specyfikacji :
Tak więc, ze względu na specyfikację, Twój przykład brzmi:
return ( GetValue(exprRef) )
gdzie
exprRef = console.log(a + b), console.log(arguments)
Który zgodnie ze specyfikacją operatora przecinka ...
... oznacza, że każde wyrażenie zostanie ocenione, aż do ostatniego elementu na liście przecinków, który stanie się wyrażeniem przypisania. Więc twój kod
return (console.log(a + b) , console.log(arguments))
będzie1.) wydrukować wynik
a + b
2.) Nic nie zostało do wykonania, więc wykonaj następne wyrażenie which
3.) drukuje
arguments
, a ponieważconsole.log()
nie określa instrukcji return4.) Ocenia jako niezdefiniowany
5.) Który jest następnie zwracany dzwoniącemu.
Więc prawidłowa odpowiedź brzmi,
return
nie ma typu, zwraca tylko wynik jakiegoś wyrażenia.Na następne pytanie:
Nie. Przecinek w JavaScript jest operatorem zdefiniowanym w celu umożliwienia łączenia wielu wyrażeń w jeden wiersz i jest definiowany przez specyfikację w celu zwrócenia wartościowanego wyrażenia tego, co jest ostatnie na liście.
Nadal mi nie wierzysz?
Zagraj z tym kodem tutaj i pomieszaj z ostatnią wartością na liście. Zawsze zwróci ostatnią wartość na liście, w twoim przypadku tak się stanie
undefined.
Na twoje ostatnie pytanie,
Znowu nie. Funkcje mają bardzo specyficzną definicję w języku. Nie będę go tutaj przedrukowywać, ponieważ ta odpowiedź jest już bardzo długa.
źródło
Testowanie, co się dzieje, gdy zwracasz wartości w nawiasach:
Daje odpowiedź
2
, więc wydaje się, że lista wartości oddzielonych przecinkami jest wynikiem ostatniego elementu na liście.Naprawdę, nawiasy nie mają tutaj znaczenia, grupują operacje zamiast oznaczać wywołanie funkcji. Zaskakujące jest jednak to, że przecinek jest tutaj legalny. Znalazłem interesujący wpis na blogu o tym, jak radzimy sobie z przecinkiem:
https://javascriptweblog.wordpress.com/2011/04/04/the-javascript-comma-operator/
źródło
return ([1, 2])
powinno wypisać obie wartości?console.log((1, 2))
return
nie jest funkcją. Jest to kontynuacja funkcji, w której występuje.Pomyśl o instrukcji
alert (2 * foo(bar));
gdziefoo
jest nazwą funkcji. Kiedy ją oceniasz, widzisz, że musisz odłożyć na chwilę resztę zdania, aby skoncentrować się na oceniefoo(bar)
. Możesz wizualizować część, którą odłożyłeś na bok, jako coś w rodzajualert (2 * _)
, z pustym miejscem do wypełnienia. Kiedy wiesz, jaka jest wartośćfoo(bar)
, podnosisz ją ponownie.To, co odłożyłeś na bok, to kontynuacja rozmowy
foo(bar)
.Wywołanie
return
przekazuje wartość do tej kontynuacji.Kiedy oceniasz funkcję wewnątrz
foo
, resztafoo
czeka, aż ta funkcja zostanie zredukowana do wartości, a następniefoo
ponownie podnosi. Nadal masz cel do ocenyfoo(bar)
, po prostu został wstrzymany.Kiedy oceniasz
return
wewnątrzfoo
, żadna część niefoo
czeka na wartość.return
nie zmniejsza się do wartości w miejscu, wfoo
którym został użyty. Zamiast tego powoduje, że całe wywołanie zostajefoo(bar)
zredukowane do wartości, a cel „ocenyfoo(bar)
” jest uważany za zakończony i zdmuchnięty.Ludzie zwykle nie mówią ci o kontynuacji, gdy dopiero zaczynasz programować. Myślą o tym jako o zaawansowanym temacie tylko dlatego, że jest kilka bardzo zaawansowanych rzeczy, które ludzie ostatecznie robią z kontynuacją. Ale prawda jest taka, że używasz ich przez cały czas, za każdym razem, gdy wywołujesz funkcję.
źródło
alert(2 * _)
do późniejszego wykorzystania w Javascript (istnieje inna notacja do tego rodzaju czynności).return
Od wewnątrzfoo
nie jest wartością; nie można było go spakować w strukturę danych, przypisać do zmiennej, poczekać chwilę, a następnie podać coś do niej później - a zwłaszcza nie można było podawać tego więcej niż raz. Ale, jak powiedziałem, zaawansowane tematy.my_if
funkcji, która zachowuje się tak samo jak wbudowanaif()then{}else{}
, i nie udaje się to zrobić, nawet jeśli pozwolisz sobie na użycie wbudowanej w niej funkcji - niezbyt zaawansowana i niezwykle pouczająca, zwłaszcza jeśli zamierzasz skończyć w kodzie, który przekazuje wywołania zwrotne.return
tutaj jest czerwony śledź. Być może interesująca jest następująca odmiana:który wyprowadza jako ostatnią linię
ponieważ funkcja w rzeczywistości nic nie zwraca. (Zwróciłby wartość zwracaną przez sekundę
console.log
, gdyby ją posiadał).W obecnej sytuacji kod jest dokładnie taki sam jak
źródło
Ciekawym sposobem zrozumienia instrukcji return jest użycie operatora void Spójrz na ten kod
Ponieważ
return
instrukcja przyjmuje jeden argument, który jest[[expression]]
i zwraca go wywołującemu na stosie, tjarguments.callee.caller
. Następnie wykona,void(expression)
a następnie zwróciundefined
, to jest ocena operatora void.źródło