Jako uzupełnienie poprzedniego posta chciałem opisać zjawisko samowywołujących się, anonimowych funkcji. Nie jest to do końca taka sama kategoria tworzenia funkcji, jak te o których pisałem wcześniej, ale myślę że mogę ją tu wepchnąć 🙂 Temat jest dość zaawansowany, szczególnie to jak możemy takie funkcje wykorzystać. Nie oznacza to jednak, że są to rzeczy niezrozumiałe.
Postaram się, jak zawsze, opisać wszystko w miarę przystępnie i podać jasne przykłady.
Czym jest taka samowywołująca się funkcja? Spójrzmy najpierw na kod, zwykłego wyrażenia funkcji
1 2 3 |
var makeBark = function(){ console.log("Bark! Bark!") } |
zmienna makeBark to tak naprawdę nic innego jak referencja do obiektu funkcji. Jak wiemy z poprzedniego posta, funkcja ta nie ma nazwy, dlatego mówi się na nią funkcja anonimowa 🙂 Jeżeli będziemy chcieli wywołać tę funkcję, to wystarczy, że użyjemy referencji, o tak:
1 |
makeBark(); |
Czyli makeBark przywołuję zawartość anonimowej funkcji, i używa operatora wywołania ‚()’ aby ją ‚odpalić’. Ale jeśli makeBark to tylko nazwa zastępcza, to znaczy, że moglibyśmy wpisać po prostu to co przechowuje, czyli naszą funkcję anonimową. Zobaczmy:
1 2 3 |
(function(){ console.log("Bark! Bark!") })(); |
Jedyny dodatek to para nawisów otaczających treść funkcji. Musimy je dodać, żeby javascript wiedział, że chodzi nam o wywołanie całości. W innym wypadku otrzymalibyśmy błąd.
Co ciekawe, możemy tak uruchomić kod na stronie, bez żadnego eventu onload. Gdy przeglądarka będzie przerabiać kod i natrafi, na taką funkcję, po prostu ją odpali.
I tyle. Tak jak pisałem. Funkcja w takiej formie zostanie od razu wywołana, gdy tylko przepływ programu na nią trafi. Nic więcej nie jest nam tutaj potrzebne. Co możemy jeszcze zrobić to dodać argumenty, tak jak w każdej funkcji. Jak to zrobić? Już pokazuję:
1 2 3 |
(function(message){ console.log(message) })("Bark! Bark!"); |
Może to wyglądać trochę „na opak”. Ale wystarczy trochę się przyjrzeć i wyraźnie widać co tu się dzieje. Mamy listę argumentów (w tym wypadku jeden message), są używane w bloku funkcji, a na koniec podajemy parametr przy wywołaniu. Nic trudnego.
Wykorzystanie samo-wywołujących się anonimowych funkcji w JavaScripcie
Ok, teraz kiedy już wiemy jak wyglądają takie funkcje, to możemy podać przykład wykorzystania ich w naturze 🙂
Jak już wspomniałem, Przykładem użycia tego typu funkcji, jest zainicjalizowanie jakiegoś kodu. Zerknijmy na ten przykład:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
<!doctype html> <html> <head> <title>playground js</title> <style type="text/css"> .clickMe { width: 150px; height: 150px; margin: 15px; background-color: #AAA; text-align: center; float: left; border:1px solid black; } .clickMe:hover { cursor: pointer; background-color: #EEE; } </style> </head> <body> <div class="clickMe">kot</div> <div class="clickMe">pies</div> <div class="clickMe">chomik</div> <div class="clickMe">rybka</div> <script type="text/javascript" src="jq.js"></script> <script type="text/javascript"> (function(){ var engine = { init : function() { this.divs = jQuery(".clickMe"); this.addClick(); }, addClick : function() { this.divs.on("click", this.alertText) }, alertText : function() { var text = jQuery(this).text(); alert(text) } } engine.init() })(); </script> </body> </html> |
Dla prostoty wszystko w jednym pliku. Aby sprawdzić jak działa wystarczy zapisać całą treść w dokumencie .html i odpalić w przeglądarce.
Ta mini „aplikacja”, ma mechanizm obsługiwany przez obiekt który inicjalizuje samo-wywołująca się funkcja. Cała logika jest zamknięta w jednym bloku kodu. Wg. mnie ten kod jest bardzo czytelny. Szybko, łatwo i przyjemnie.
Warto zaznaczyć, że samowywołujące się anonimowe funkcję są również bazą do bardzo popularnego wśród programistów JS wzorca modułu. To jest jednak temat na osobny post 🙂
myślę, że warto byłoby dopisać, że główną zaletą i celem takiego podejścia jest zabezpieczenie się przed zaśmiecaniem przestrzeni globalnej – ale ogólnie dobrze napisane moim zdaniem 😉
Oczywiście! W ten sposób przede wszystkim tworzy nam się osobny, czyściutki scope. Dzięki za dodanie tego info 🙂