Dlaczego przekazywanie dużych funkcji anonimowych jako argumentów do innych funkcji jest tak powszechnie akceptowane w JavaScript?

27

Mam opinię (z pewnością niektórzy ją podzielą), że przekazywanie anonimowych funkcji, które zawierają więcej niż kilka wierszy kodu, ponieważ argumenty innych funkcji drastycznie wpływają na czytelność i samok dokumentację, do tego stopnia, że ​​czuję, że być znacznie lepszym dla każdego, kto prawdopodobnie użyje tego kodu, aby zadeklarować nazwaną funkcję. Lub przynajmniej przypisz tę anonimową funkcję do zmiennej przed zadeklarowaniem funkcji głównej

Jednak wiele bibliotek JavaScript (jQuery, d3.js / NVD3.js), aby podać kilka przykładów, używaj dużych funkcji w ten sposób.

Dlaczego jest to tak szeroko akceptowane w JavaScript? Czy jest to kwestia kulturowa, czy też są zalety, których mi brakuje, które sprawiłyby, że użycie jest bardziej preferowane niż zadeklarowanie nazwanej funkcji?

Adam Copley
źródło
1
Prawdopodobnie ma to wiele wspólnego z używaniem zamknięć . Może to mieć również związek z tym, że nie chce ujawniać rzeczywistej funkcji światu zewnętrznemu (dlatego jest anonimowy).
Robert Harvey
3
@RobertHarvey Innymi słowy, jest to obejście dla JavaScript, który nie ma publicznych i prywatnych ?
Mason Wheeler
2
W wielu miejscach duża anonimowa funkcja jest bardziej podobna do bloku i ogólnie czuje się całkiem dobrze, gdy się do tego przyzwyczaisz. Zasady określania zakresu wspierają nawet odczucie bloku.
5
@MasonWheeler: To zależy od twojej perspektywy. Programista lub programista ECMAScript może to powiedzieć publici privatesą obejścia tego problemu dla braku odpowiednich zamknięć.
Jörg W Mittag
1
@ JörgWMittag Hooray for Racket, oficjalny sponsor językowy XKCD 927!
Mason Wheeler

Odpowiedzi:

23

Trzy główne powody, o których mogę myśleć:

  1. Dostęp do zakresu nadrzędnego
  2. Prywatność
  3. Redukcja nazw zdefiniowanych w wyższych zakresach

Dostęp do zakresu nadrzędnego: Definicje funkcji wbudowanych umożliwiają kodowi wbudowanemu dostęp do zmiennych zdefiniowanych w zakresach nadrzędnych. Może to być bardzo przydatne dla wielu rzeczy i może zmniejszyć ilość lub złożoność kodu, jeśli zostanie wykonana poprawnie.

Jeśli umieścisz kod w funkcji zdefiniowanej poza tym zakresem, a następnie wywołasz kod, będziesz musiał przekazać dowolny stan nadrzędny, który chciałby uzyskać dostęp do funkcji.

Prywatność: kod wewnątrz wbudowanej anonimowej definicji jest bardziej prywatny i nie może być wywoływany przez inny kod.

Redukcja nazw zdefiniowanych w wyższych zakresach: Jest to najważniejsze w przypadku działania w zakresie globalnym, ale wbudowana anonimowa deklaracja nie wymaga definiowania nowego symbolu w bieżącym zakresie. Ponieważ Javascript nie wymaga natywnego użycia przestrzeni nazw, mądrze jest unikać definiowania większej liczby globalnych symboli niż jest to wymagane minimalnie.


Od redakcji: Wydaje się, że stało się to kulturową rzeczą w Javascript, gdzie deklarowanie czegoś anonimowo wewnątrz jest uważane za „lepsze” niż definiowanie funkcji i wywoływanie jej, nawet gdy nie jest używany dostęp do zakresu nadrzędnego. Podejrzewam, że początkowo było to spowodowane globalnym problemem zanieczyszczenia przestrzeni nazw w Javascripcie, a następnie być może z powodu problemów z prywatnością. Ale teraz zmieniło się to w coś kulturowego i widać to w wielu publicznych kodeksach (takich jak te, o których wspominasz).

W językach takich jak C ++ większość uważa, że ​​posiadanie jednej gigantycznej funkcji, która rozciąga się na wiele stron / ekranów, nie jest idealną praktyką. Oczywiście, C ++ ma wbudowaną przestrzeń nazw, nie zapewnia dostępu do zakresu nadrzędnego i ma funkcje prywatności, więc może być całkowicie zmotywowana przez czytelność / konserwację, podczas gdy Javascript musi używać wyrażenia kodu, aby uzyskać prywatność i dostęp do zakresu nadrzędnego. Wygląda na to, że JS zostało zmotywowane w innym kierunku i stało się czymś kulturowym w języku, nawet jeśli rzeczy, które motywowały ten kierunek, nie są potrzebne w konkretnym przypadku.

jfriend00
źródło
Ponieważ programista C ++ niedawno przeniósł się do JS na dużą część mojej pracy, ta odpowiedź ma sens, szczególnie punkt „dostępu do zakresu nadrzędnego” - naprawdę jest w stanie znacznie uprościć twój kod. Jeden nitpick - C ++ zapewnia dostęp do zakresu nadrzędnego w lambda C ++ 11 :) Zdecydowanie jednak +1.
Commander Coriander Salamander
8

Anonimowe funkcje są używane w JavaScript o wiele więcej celów niż w większości języków.

Po pierwsze, są one używane do przestrzeni nazw i określania zakresu bloków. Do niedawna w JavaScript brakowało modułów lub jakiegokolwiek innego mechanizmu przestrzeni nazw, który doprowadził do użycia anonimowych funkcji w celu zapewnienia tej funkcjonalności poprzez Wzorzec Modułu. Nazwy tych funkcji nie przyniosłyby absolutnie żadnej korzyści. W mniejszej skali, ze względu na brak do niedawna braku zakresu JavaScript w blokach , podobny wzór zastosowano do naśladowania zakresu bloków; przede wszystkim w ciele pętli. Użycie w tym przypadku funkcji o nazwie byłoby aktywnie zaciemniające.

Po drugie, anonimowe funkcje JavaScript są często używane z funkcjami wyższego rzędu, które naśladują struktury kontrolne. Na przykład eachmetoda jQuery . Wątpię, czy wyodrębniasz każde ciało pętli lub if-rozgałęzienie w funkcję, ilekroć ma ona więcej niż kilka linii. W tym przypadku obowiązuje ta sama logika.

Ostatni powód jest taki, że programowanie oparte na zdarzeniach jest powszechne w JavaScript, co zwykle prowadzi do niezamierzonego przekazywania kodu stylu . Wykonujesz wywołanie AJAX i rejestrujesz oddzwonienie, które po wykonaniu spowoduje kolejne wywołanie AJAX i zarejestruje oddzwonienie itp. Gdyby wywołania były raczej synchroniczne niż asynchroniczne, byłaby to po prostu prosta sekwencja kodu w jednym zakresie leksykalnym . Znowu wątpię, czy wyodrębniłbyś co kilka linii kodu liniowego w funkcję.

Istnieją również czynniki kulturowe i, z powyższych powodów, między innymi anonimowe funkcje są o wiele bardziej powszechne w JavaScript niż w wielu innych językach i są używane wygodniej / luźniej niż w wielu innych językach.

Derek Elkins
źródło
Moje własne, być może naiwne struktury w kodowaniu C ++ czasami wykorzystywały zasady kodowania opartego na zdarzeniach i wywołań zwrotnych z JavaScript poprzez std :: function i lambdas. W moim przypadku jest to częściowo spowodowane tym, że robię kod interfejsu użytkownika w C ++ i nie chcę wykonywać operacji blokujących. Jestem ciekawy, czy praktyki JavaScript są po prostu przydatne dla każdego, o ile język dobrze je obsługuje.
Katana314