Funkcje: Tworzenie funkcji w JavaScripcie

W mojej karierze pracy z JavaScriptem nic, nie było dla mnie tak mgliste i mylące jak mnogość sposobów na stworzenie nowej funkcji. Najgorsze było to, że żadna z książek, które czytałem, nie wyjaśniała definitywnie tego tematu. Internet, też nie był zbyt pomocny, zresztą, nie wiedziałem nawet jak pytać o ten problem googla.

Teraz już wiem na co zwracać uwagę i rozumiem, że wiedza ta jest bardzo ważna. W tym poście opiszę sposoby na tworzenie funkcji w JavaScripcie. Czym różnią się między sobą i które są dobre, a które niekoniecznie. Jak zawsze wszystko zilustrujemy przykładami.

Tworzenie funkcji w JavaScripcie

Konstruktor new Function

Najmniej chyba popularna metoda tworzenia nowych funkcji. Jednak można się spotkać z nią w niektórych publikacjach. Ponieważ każda funkcja to instancja klasy Function, możemy stworzyć ją tak, jakbyśmy tworzyli każdy inny obiekt.

Do konstruktora przekazujemy wszystkie argumenty jako ciągi znaków. Ostatni argument to treść jaką ma mieć tworzona funkcja. W naszym wypadku zwraca ona sumę dwóch poprzednich argumentów.

Osobiście odradzam używania tego sposobu do tworzenia nowych funkcji. Szczerze mówiąc, nie wiem czy ktokolwiek z niego korzysta. Problemem jest to, że musielibyśmy trzymać dużo kodu w ciągach znaków. Nie jest to wygodna sytuacja. Edytory tekstu, nie będą nam kolorować składni a wszelkie narzędzia do debugowania kodu, będą miały znacznie utrudnioną pracę.

Ponieważ jest mało użyteczna, nie będziemy szczegółowo przyglądać się tej metodzie i przejdziemy szybko do kolejnej.

Deklaracja funkcji

Deklaracja to najpopularniejsza metoda tworzenia funkcji. Jest bardzo lubiana przez programistów, ponieważ pozwala na dużą swobodę podczas pisania kodu. Czemu? Zaraz wyjaśnię. Najpierw przyjrzyjmy się samej metodzie:

Osobiście uważam, że składnia wygląda dużo czytelniej niż w przypadku zastosowania konstruktora Function.

Warto zaznaczyć, że jak każdy obiekt, funkcje również posiadają swoje własne właściwości. Jedną z nich jest name. zwraca ona identyfikator danej funkcji czyli to co w deklaracji znajduję się po słowie function. Spójrzmy

Identyfikator może zostać wykorzystany do wywołania funkcji. Jest on dostępny w zasięgu (scope), w którym tworzymy funkcję, oraz w jej wnętrzu. Przykład:

Ciekawym aspektem związanym z deklaracją funkcji jest tak zwany hoisting, czyli z angielskiego podnoszenie lub dźwignięcie. Na czym to polega. Otóż deklaracje funkcji, tak samo jak deklaracje zmiennych, podczas parsowania kodu przez przeglądarkę, są przenoszone na samą górę aktualnego zasięgu. Tam są ustawiane w takiej kolejności, w jakiej zostały zapisane. Oznacza to w praktyce, że możemy wywoływać w kodzie funkcje, zanim je zadeklarujemy. A działa to tak:

Chociaż na pierwszy rzut oka wydaje się to dość wygodne, to może to prowadzić do dość kłopotliwych sytuacji. Rozpatrzmy taki przykład:

Pierwsza myśl, może sugerować, że kod zwróci nam 0. W końcu wywołanie funkcji następuję zaraz po zadeklarowaniu funkcji wykonajObliczenia, w której wykonuje się odejmowanie. Ale nie jest tak. Kod zwróci nam 10. Dlatego, że wszystkie deklaracje są hoistowane. Dla przeglądarki kod wygląda tak:

Pierwsza deklaracja jest nadpisana przez drugą, i dopiero później następuje wykonanie. To sprawia, że możemy mieć problem z np. takim przeładowywaniem funkcji. Czyli ze zmienianiem treści funkcji, która wcześniej robi coś innego. Mogę jeszcze bardziej udziwnić zachowanie tego kodu:

Przeanalizujmy. zwrotWyniku, jest hoistowany, więc możemy go wywołać przed deklaracją. Robimy to w console logu. Wewnątrz tej funkcji mamy dwie kolejne, obie nazwane tak samo. Jednak między nimi znajduje się wyrażenie return. Na pewno nie raz słyszeliście, że kod po return jest nieosiągalny. I to może was zgubić. Hoistowanie odbywa się przed jakimkolwiek odpalaniem kodu. Dla interpretora, return, znajduje się na końcu bloku. Reszta, to historia którą już znamy. Wykonuje się funkcja z dodawaniem.

Nie są to bardzo trudne rzeczy, ale należy o nich pamiętać. Przejdźmy do kolejnej metody tworzenia funkcji

Wyrażenie funkcji

Ta metoda wykorzystuje fakt, że funkcje możemy przypisywać do zmiennych. Nazwa wywodzi się z faktu, że tworzenie funkcji jest częścią większego wyrażenia. Wygląda to w ten sposób:

Deklarujemy zmienną i operatorem ‚=’ przypisujemy do niej funkcję. Właściwość name tej funkcji zwraca nam interesujące rzeczy.

Do tego zmienna do której przypisujemy funkcję, w ogóle nie jest widoczna we wnętrzu funkcji

Przejdźmy teraz to kwesti hositingu. Jak zachowują się wyrażenia funkcji, kiedy próbujemy wywołać je przed ich utworzeniem. Najlepiej zilustruje to kolejny przykład

Czyli wyrażenia funkcji się nie hoistują! Nie do końca. Hoisting występuje, ale wygląda trochę inaczej niż w przypadku deklaracji. oto jak ten kod widzi przeglądarka:

Hoistowane są same deklaracje zmiennych, nie przypisanie. Dlatego kod poniżej nie zadziała:

Konsola wypluje nam błąd, ponieważ wykonajObliczenie jest undefined w momencie wywołania. Dla przeglądarki wygląda to tak:

Bonus – nazwane wyrażenie funkcji

Na koniec mała ciekawostka. Otóż możemy jeszcze spotkać się z czymś takim:

Wyrażenie funkcji, które ma podaną nazwę po słowie function. Spróbujmy wywołać tę funkcję.

Skoro nie możemy użyć tej nazwy, to po co nam ona? Otóż możemy, ale tylko wewnątrz funkcji. A robimy to np tak:

Jest to ciekawe zachowanie, o którym warto pamiętać. Czasem możemy potrzebować odwołać się do funkcji w jej wnętrzu.

O zasięgu funkcji, napiszę jeszcze parę słów w innym poście

Podsumowanie

Na koniec małe podsumowanie. Która metoda jest najlepsza. Nie mam tutaj dobrej odpowiedzi. Na pewno powinno się unikać tworzenia funkcji używając operatora new. Co do dwóch pozostałych… to kwestia preferencji.

Przez hoisting, deklaracje funkcji są łatwe w użyciu, ale pozwalają też na niedbalstwo. Wiem dobrze, bo sam ich używam 🙂

Wyrażenia funkcji z kolei, są bardziej podatne na błędy, ale przez to zmuszają programistę do pisania przemyślanego kodu.

Na pewno jako programista javascriptu, trzeba znać każdą z tych metod i zdawać sobie sprawę z ich słabych i mocnych stron. Mam nadzieję, że tym krótkim wpisem, pomogłem wam zrozumieć ten aspekt języka JavaScript.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *