Ziel des Artikels: Den Sinn folgenden Konstrukts verstehen
(function(window, document, undefined) { //some fancy code })(this, document);
Mag auf den ersten Blick für den nicht täglich mit Javascript schaffenden Menschen beängistend aussehen. Aber der Reihe nach. Eine ähnliche Konstruktion kommt übrigens in jQuery zum Tragen (siehe source).
Anonym?
Erstmal ist die Funktion anonym, also ohne Namen. Einfach aus dem Grund, weil sie keinen Namen braucht, da sie sich ja selbst aufruft. Man könnte ihr übrigens einen Namen geben, funktionieren würde es trotzdem. Vereinfacht sieht das dann z.B. so aus:
(function nichtMehrAnonym() { //some fancy code })();
Vorteil: Wenn wir vorhaben, die Funktion aus sich selbst heraus nochmal aufzurufen, ist das so bequemer möglich (Rekursion).
Warum die Parameter?
window hat innerhalb der Funktion den Wert, den this außerhalb der Funktion hat. Da sich die Funktion im globalen Scope befindet, ist window dasselbe wie this. Leicht festzustellen hierdurch:
<script> alert(this === window); //true </script>
Man kann natürlich auch window anstelle von this schreiben. Selbiges geschieht mit document, für das man auch this.document schreiben könnte, da das document ein Kind des window ist.
Stellen sich drei Fragen zu den Parametern:
- Warum sollte man sowas tun?
- Darf man das?
- Was ist mit undefined?
Antwort zu 1): Hat zwei Gründe. Der erste ist Performance. Man spart sich einen Schritt nach oben im Variablenscope, weil wir nun innerhalb unserer Funktion quasi lokal window und document rumfliegen haben. Javascript schaut nämlich zuerst die lokalen Variablen und dann erst die globalen an, also einen Schritt gespart – auch wenn der Gewinn minimal ist. Der zweite Grund ist: Minification und dadurch Codegröße. Jage ich den Code durch einen Javascript-Minifier wird daraus z.B.
(function(w, d, u) { //some fancy code })(this, document);
Wenn ich nun innerhalb meiner Funktion vorher document.getElementById(…) hatte, habe ich nun d.getElementById(…). Schön zu sehen im Source von jQuery in der minified-Variante.
Antwort zu 2 und 3): Ja, man darf!
<script> alert(typeof undefined); //undefined undefined = "evil"; alert(typeof undefined); //string </script>
Noch Fragen? Mal eiskalt undefined überschrieben. Und genau das ist auch der Grund, warum undefined erwartet, aber beim Aufruf nicht übergeben wird. Angenommen ich habe folgendes:
(function() { if (x === undefined) { //... } })();
Jetzt geht jemand daher, und belegt im globalen Scope fröhlich undefined mit true. Würde einiges an Verwirrung in meiner Funktion stiften. Deswegen gehen wir auf Nummer sicher und bewahren uns ein „wahres“ undefined in unserer Funktion durch einen nicht übergebenen Parameter, der auch dann erhalten bleibt wenn jemand außerhalb Schabernack treibt. Gut, haben wir das mit den Parametern also geklärt.
Und wozu das Ganze?
Erstmal wie angesprochen ein Quäntchen Performance durch einen eingesparten Schritt im Scope. Aber das größere Argument ist: Der globale Variablenraum wird nicht mit unnötig vielen Variablen verschmutzt. Da alles in einer Funktion gekapselt ist, sind die Variablen lokal, die sonst global wären. So sind z.B. Libraries gut vor Überschneidungen von internen Variablennamen mit dem Code des Nutzers bewahrt. Und letztlich: Der „Booah, cool“-Effekt.
Geht da noch was?
Aber ja! Die self-executing-function darf auch fleißig returnen. Beispiel?
var myvar = (function() { return "somestuff"; })(); alert(myvar === "somestuff"); //true
Credits an Paul Irish für die sehr nett gemachten Screencasts über Tricks im jQuery-Source, zu sehen hier und hier.
Schöner Artikel
Obwohl ich mich jetzt schon ein bisschen intensiver mit Javascript aufgrund der ganzen aufgekommenen clientseitigen Frameworks a la ExtJs / jQuery beschäftigt habe, ist mir Javascript immer noch ein bisschen suspekt. Ich wurde bis heute einfach nicht so ganz warm mit der Sprache, obwohl ich sie in den wichtigen Punkten verstehe.
Und Paul Irish rockt :-)
Hi Ralph, danke für die Blumen ;). Ich verweise mal dezent auf die (coolen) Slides eines Javascript-Workshops, den mein Chef demletzt firmenintern gegeben hat: Programming professional Javascript while staying sane. Da waren auch noch einige neue Sachen für mich dabei. Ah, und der kurze Artikel hier ist auch was feines.
Da dachte ich selbstausführende anonyme Funktionen sind ja keine Wissenschaft aber der Artikel war tatsächlich lehrreich. Also der Kniff mit undefined war mir neu, sehr schön erläutert!
merci. Da mir gestern beim Durchstöbern der deutschen Bloggosphäre aufgefallen ist, dass es eigentlich niemanden gibt, der sich ernsthaft mit JS beschäftigt wird demnächst bissl mehr dazu kommen.
Schön :-)
Hallo David,
vielen Dank für Deinen Artikel – aber … warum überhaupt eine anonyme Funktion erstellen, die sofort ausgeführt wird? Warum nicht einfach „plain“ Zeile für Zeile die Anweisungen runter schreiben, eben ohne Funktion?
Besten Dank und Grüße,
Frank