Javascript: selbstausführende, anonyme Funktionen

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:

  1. Warum sollte man sowas tun?
  2. Darf man das?
  3. 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.


Deprecated: Directive 'allow_url_include' is deprecated in Unknown on line 0