Samouczek (dla Javascript), który wykonuję, sugeruje napisanie takiej funkcji:
function sayHello() {
//Some comments explaining the next line
window.alert("Hello");
}
Czy oprócz zaciemnienia istnieją korzyści z pisania czegoś takiego w prawdziwym życiu? Jeśli tak, jakie są korzyści?
language-agnostic
functions
Daniel
źródło
źródło
Odpowiedzi:
Proszę wybacz mi pamięć, jeśli mam ten niepoprawny ... JavaScript nie jest moim preferowanym językiem implementacji.
Istnieje kilka powodów, dla których ktoś chciałby, aby funkcja no arg zawijała inne wywołanie funkcji. Chociaż proste wezwanie do
window.alert("Hello");
jest czymś, co można sobie wyobrazić, zamiast tego dzwoniąc bezpośrednio zamiastsayHello()
.Ale co, jeśli jest coś więcej? Masz tuzin miejsc, do których chcesz zadzwonić
sayHello()
iwindow.alert("Hello");
zamiast tego napisałeś . Teraz chcesz to zrobićwindow.alert("Hello, it is now " + new Date())
. Jeśli wszystkie te połączenia zostały opakowane, gdysayHello()
zmienisz je w jednym miejscu. Jeśli tego nie zrobiłeś, zmieniasz go w kilkunastu miejscach. To dotyczy „ Nie powtarzaj się” . Robisz to, ponieważ nie chcesz tego robić kilkanaście razy w przyszłości.W przeszłości pracowałem z biblioteką i18n / l10n, która używała funkcji do lokalizacji tekstu po stronie klienta. Rozważ
sayHello()
funkcję. Możesz go wydrukować,hola
gdy użytkownik jest zlokalizowany na język hiszpański. Może to wyglądać mniej więcej tak:Chociaż nie tak działała biblioteka. Zamiast tego miał zestaw plików, które wyglądały następująco:
Następnie biblioteka wykryje ustawienia języka przeglądarki, a następnie utworzy funkcje dynamiczne z odpowiednią lokalizacją jako wartość zwracaną dla wywołania funkcji bez kłótni na podstawie odpowiedniego pliku lokalizacji.
Nie jestem wystarczającym koderem Javascript, aby powiedzieć, czy to dobrze, czy źle ... po prostu to było i może być postrzegane jako możliwe podejście.
Chodzi o to, że zawinięcie wywołania innej funkcji w jej własną funkcję jest często bardzo przydatne i pomaga w modularyzacji aplikacji, a także może skutkować łatwiejszym odczytem kodu.
Poza tym pracujesz z samouczka. Na początku należy wprowadzić rzeczy tak prosto, jak to możliwe. Wprowadzenie wywołań funkcji stylu varargs od samego początku może spowodować bardzo mylący kod dla osoby, która nie jest zaznajomiona z kodowaniem w ogóle. O wiele łatwiej jest przejść od braku argumentu, do argumentów, do stylu varargs - z każdym budowaniem na poprzednich przykładach i zrozumieniu.
źródło
window.alert
jest również często używany jako symbol zastępczy podczas programowania, dopóki nie można zaprojektować / wdrożyć ładnego modalu / wyskakującego okienka, więc podobnie jak w przypadku języka, można go znacznie łatwiej wyłączyć. Lub jeśli już go masz, aktualizacja projektu kilka lat później może wymagać podobnych zmian.Myślę, że czasami jest to przydatne do ukrywania implementacji.
A to daje elastyczność, aby zmienić to później
źródło
centralizacja: chociaż implementacja jest długa na jedną linię, jeśli jest to linia, która często się zmienia, prawdopodobnie wolisz ją zmienić w jednym miejscu, niż gdziekolwiek nazywa się Hello.
minimalizowanie / ukrywanie zależności: kod klienta nie musi już wiedzieć, że istnieje obiekt okna, a nawet możesz zmienić całą implementację bez wpływu na kod klienta
realizacja umowy: kod klienta może oczekiwać modułu z funkcją sayHello. W tym przypadku, nawet jeśli banalna, funkcja musi tam być.
spójność poziomów abstrakcji: jeśli kod klienta korzysta z operacji wysokiego poziomu, w twoim interesie jest napisanie kodu klienta w kategoriach „sayHello, sayBye” i niektórych innych funkcji (sayXXX) zamiast obiektów okna. Rzeczywiście, w kodzie klienta możesz nawet nie chcieć wiedzieć, że istnieje coś takiego jak obiekt „okna”.
źródło
Zadziwiające, że żadna inna osoba nie wspomniała o testowaniu.
Ta konkretna „owinięta” linia, którą wybrałeś
window.alert('hello')
, jest w rzeczywistości doskonałym tego przykładem. Testowanie wszystkiego, co dotyczy tegowindow
obiektu, jest naprawdę bardzo bolesne. Pomnóż to przez 1000 razy w swojej aplikacji i gwarantuję, że programiści ostatecznie zrezygnują z testowania. Z drugiej strony dość łatwo jest po prostu zablokowaćsayHello
funkcję szpiegiem i przetestować, że została wywołana.Bardziej praktyczny przykład - bo tak naprawdę, kto tak naprawdę używa
window.alert(...)
w kodzie produkcyjnym? - sprawdza zegar systemowy. Na przykład byłoby to zawijanieDateTime.Now
w .NET,time(...)
w C / C ++ lubSystem.currentTimeMillis()
w Javie. Ty naprawdę chcesz zawinąć te w zależności, które można wstrzykiwać, ponieważ są one nie tylko (prawie) niemożliwe wyśmiewać / fałszywe, są one tylko do odczytu i nie deterministyczny . Każdy test obejmujący funkcję lub metodę, która bezpośrednio wykorzystuje funkcję zegara systemowego, jest bardzo podatny na przejściowe i / lub przypadkowe awarie.Rzeczywiste opakowanie jest funkcją 1-liniową
return DateTime.Now
- ale to wszystko, czego potrzebujesz, aby wziąć źle zaprojektowany, niepodlegający testom obiekt i sprawić, że będzie czysty i testowalny. Możesz zastąpić owinięcie fałszywym zegarem i ustawić jego czas na cokolwiek chcesz. Problem rozwiązany.źródło
Jak powiedział Doval, ten przykład prawdopodobnie po prostu próbuje zapoznać cię z funkcjami. Ale ogólnie jestem przydatny. Zwłaszcza poprzez podanie niektórych, ale nie wszystkich argumentów, i przekazanie pozostałych, możesz stworzyć funkcję bardziej specyficzną dla wielkości liter z funkcji bardziej ogólnej. Jako trywialny przykład rozważ funkcję sortowania, która zajmuje tablicę do sortowania i funkcję komparatora do sortowania. Określając funkcję komparatora, która porównuje wartość liczbową, mogę utworzyć funkcję sortByNumericalValue, a wywołania tej funkcji są znacznie bardziej jasne i zwięzłe.
źródło
Myślenie, które kryje się za twoim pytaniem, wydaje się następujące: „Dlaczego po prostu nie pisać
alert("Hello");
bezpośrednio? To całkiem proste”.Odpowiedź brzmi po części dlatego, że tak naprawdę nie chcesz dzwonić
alert("Hello")
- po prostu chcesz się przywitać.Lub: Po co przechowywać kontakty w telefonie, skoro można po prostu wybierać numery telefonów? Ponieważ nie chcesz pamiętać wszystkich tych liczb; ponieważ wybieranie numerów jest uciążliwe i podatne na błędy; ponieważ liczba może się zmienić, ale nadal jest to ta sama osoba na drugim końcu. Ponieważ chcesz dzwonić do ludzi , a nie do numerów.
To właśnie rozumieją terminy takie jak abstrakcja, pośrednictwo, „ukrywanie szczegółów implementacji”, a nawet „ekspresyjny kod”.
To samo rozumowanie dotyczy używania stałych zamiast pisania surowych wartości wszędzie. Ty mógł tylko pisać
3.141592...
za każdym razem trzeba gatunku, ale na szczęście nie maMath.PI
.Możemy również spojrzeć na
alert()
siebie. Kogo obchodzi, w jaki sposób konstruuje i wyświetla to okno dialogowe z ostrzeżeniem? Chcesz tylko ostrzec użytkownika. Pomiędzy pisaniemalert("Hello")
a zmianą pikseli na ekranie jest głęboki, głęboki stos kodu i sprzętu, przy czym każda warstwa mówi następnej, czego chce, a następna warstwa zajmuje się szczegółami, dopóki najgłębsza możliwa warstwa nie zmieni niektórych bitów w pamięć wideo.Naprawdę nie chcesz tego robić samemu, żeby się przywitać.
Programowanie - cóż, każde zadanie, naprawdę - polega wyłącznie na dzieleniu złożonych problemów na porcje do zarządzania. Rozwiązanie każdej części daje ci klocek, a przy wystarczającej liczbie prostych klocków możesz budować duże rzeczy.
To jest algebra.
źródło
Dobrym pomysłem jest oddzielenie obliczania wartości (wyrażeń) od wykonywania akcji (instrukcji). Chcemy precyzyjnej kontroli nad tym, gdzie i kiedy zostaną podjęte działania (takie jak wyświetlanie komunikatów), ale przy obliczaniu wartości wolelibyśmy pracować na bardziej abstrakcyjnym poziomie i nie musielibyśmy się martwić, w jaki sposób te wartości są obliczane.
Funkcja, która oblicza tylko wartość zwracaną, używając tylko podanych argumentów, nazywa się czysta .
„Funkcja”, która wykonuje akcję, jest w rzeczywistości procedurą , która ma efekt .
Wszelkie efekty powstałe podczas obliczania wartości nazywane są efektami ubocznymi i lepiej jest ich unikać, gdy to możliwe („Potrzebowałem tylko tego ciągu, nie wiedziałem, że spowoduje to uszkodzenie bazy danych!”).
Aby zminimalizować ryzyko wystąpienia efektów ubocznych, powinniśmy unikać przesyłania zbyt dużej ilości danych do naszych procedur lub dokonywania w nich jakichkolwiek obliczeń; jeśli trzeba wcześniej wykonać pewne obliczenia, zwykle lepiej jest to zrobić osobno w czystej funkcji, a następnie przekazać do procedury tylko wymagany wynik. Dzięki temu cel procedury jest jasny i zmniejsza szansę, że zostanie ona ponownie wykorzystana później w ramach obliczeń (czysta funkcja może zostać ponownie użyta).
Z tego samego powodu powinniśmy unikać przetwarzania wyników w ramach procedury. Lepiej zwrócić wynik (jeśli w ogóle) naszą akcję i wykonać dowolne dalsze przetwarzanie przy użyciu czystych funkcji.
Jeśli będziemy przestrzegać tych zasad, możemy skończyć z procedurą podobną
sayHello
, która nie potrzebuje żadnych danych i nie daje rezultatu. Dlatego najlepszym interfejsem jest brak argumentów i nie zwracanie wartości. Jest to lepsze niż na przykład wywołanie „console.log” w trakcie niektórych obliczeń.Aby zmniejszyć potrzebę efektów podczas obliczeń, możemy mieć obliczenia, które zwracają procedury ; na przykład. jeśli musimy zdecydować o działaniu, które możemy podjąć, możemy mieć czystą funkcję, wybrać procedurę i zwrócić ją, zamiast wykonywać ją bezpośrednio.
Podobnie, aby zmniejszyć potrzebę obliczeń podczas procedur, możemy mieć procedury przyjmujące inne procedury jako parametry (być może wynik funkcji); na przykład. biorąc szereg procedur i uruchamiając jeden po drugim.
źródło
setFoo
połączeń, ponieważ oznacza to zmienne dane. Zmiana zawartości zmiennych / właściwości jest efektem, który powoduje, że wszystkie obliczenia wykorzystujące te dane stają się nieczyste. Nie polecamexecute
połączeń per se, ale byłoby zalecanerunFoo
procedury wykonywania czynności na podstawie ich argumentów.Powiedziałbym, że jest to kombinacja odpowiedzi udzielonych przez @MichaelT i @Sleiman Jneidi.
Być może w kodzie jest wiele miejsc, w których chcesz przywitać użytkownika wiadomością Hello, więc spakuj ten pomysł w metodzie. W metodzie możesz ją przetłumaczyć lub rozwinąć na zwykłym „Cześć”, wyświetlając dłuższy tekst. Możesz także skorzystać z miłego okna dialogowego JQuery zamiast alertu.
Chodzi o to, że wdrożenie jest w jednym miejscu. Musisz tylko zmienić kod w jednym miejscu. (SayHello () jest być może zbyt prostym przykładem)
źródło