JavaScipt-Code

18. Juli 2014 von & gespeichert unter Coding.

Im vorangegangenen Blog-Post zur JavaScript-Funktion habe ich einige Grundlagen zum Funktions-Objekt in JavaScript etabliert. Ich demonstrierte in kleinen Beispielen die Vielseitigkeit und schloss den Artikel mit Beispielen für eine simple objektorientierte Programmierung in JavaScript. Wer sich mit fortgeschrittenen Methoden beschäftigen mag, dem seien Bibliotheken wie Klass, Classy oder FastClass sowie andere, in JavaScript kompilierende Programmiersprachen wie CoffeeScript oder TypeScript empfohlen. Teil 2 beschäftigt sich nun mit Closures.

Ein Closure ist ein geläufiges Konstrukt für jeden JavaScript-Entwickler, eine erste Berührung damit hat jeder Anfänger mit den Event-Handlern, z.B. für Maus-Ereignisse (onclick u.a.). Event-Handler werden meist als anonyme Funktionen übergeben, wobei Closures nicht zwangsläufig anonym sein müssen. Die wichtigere Eigenschaft ist aber, dass sie den Kontext ihrer Erstellung behalten und nutzen können. Ein kleines Beispiel soll das verständlich machen:

Unser kleiner Währungsrechner im Beispiel ist eine einfache Implementierung mit Hilfe eines Closures. Die Funktion getConcurrenyConverter gibt eine neue Funktion zurück, die ihre Umgebung an sich bindet. Diese Umgebung ist der Wert von x. Die zwei Anwendungen für dollar2euro sowie euro2dollar verdeutlichen das, in dem sie mit den korrekten Umrechnungswerten erzeugt wurden. Dieses kleine Beispiel verdeutlicht schon sehr gut, wie mächtig Closures sein können. Um ein wenig Theorie einzuwerfen: in unserem Beispiel ist getConcurrenyConverter eine Funktion höherer Ordnung, da sie eine neue Funktion zurückliefert. Das ist möglich, da Funktionen in JavaScript sogenannte „First-Class-Objekte“ sind, sie also wie jedes andere Objekt (Zahlen, Strings, Arrays, Objekte) als Argument oder Rückgabewert einer Funktion genutzt oder auch einfach in einer Variable abgelegt werden können.

Weniger Code

Closures können auch zu einer saubereren Code-Basis führen. So muss man temporäre Werte nicht unbedingt global vorhalten, sondern kann sie auch in einem Closure binden. Ein schönes Beispiel dazu wäre ein Drag&Drop mit jQuery für ein HTML-Element:

Dieses Beispiel ist schon ein wenig umfangreicher, aber die ganze Magie befindet sich eigentlich nur in der Funktion getDragHandler(). Zum Ausprobieren reicht es lediglich, die Website http://jquery.com/ aufzurufen und den Code in der Webkonsole auszuführen. Klickt man nun auf das jQuery-Logo, lässt es sich bei gedrückter Maustaste umherbewegen. Herzlichen Glückwunsch, ein erstes interaktives Beispiel für Closures!

OOP-Closures

Dank der Dynamik und Vielseitigkeit von JavaScript lassen sich auch Closures bzw. deren Eigenschaften auf andere Aspekte übertragen, z.B. der objektorientierten Programmierung. Persönlich bin ich kein großer Fan der prototypischen Vererbung (also über Klasse.prototype). Ein großer Nachteil ist das Fehlen privater, also nach außen nicht sichtbarer Eigenschaften und Funktionen. Da ich auch nicht extra eine weitere Bibliothek in meine Projekte einbinden möchte, greife ich gerne auf eine zweite Form der Vererbung zu. Dazu ein Beispiel:

Das ist natürlich jetzt ein deutlich umfangreicheres Beispiel1, aber es zeigt eine schöne und gut funktionierende Struktur. Zunächst wird die Klasse in eine Funktion eingehüllt, die nur meine Klasse zurückliefert. Alles andere bleibt für die äußere Umgebung unsichtbar. Die Variable STATIC_OPTION ist z.B. nur innerhalb der Hüllenfunktion sichtbar, sie ist also privat. Das Gleiche gilt für die innere Klasse Item. Die eigentliche Klasse LinkedList enthält auch einige Schmankerl. Zunächst binde ich den this-Kontext an die (private) Variable self.2 Genauso wie die nachfolgenden Variablen3 sowie Funktionen ist diese Variable privat. Erst die an self gebundenen Funktionen und Variablen sind öffentlich. Nach der Deklaration der Klasse, binde ich noch statische Variablen an ihr. Diese sind öffentlich, weil sie gemeinsam mit der Klasse exportiert werden. Ich hoffe, die Kommentare helfen beim Verstehen der unterschiedlichen Kapselungen.

Was hat das nun aber mit Closures zu tun? Nun ja, ganz einfach: dieses Beispiel ist eine gebündelte Struktur von Closures. Die zurückgegebene Klasse LinkedList ist eine Closure, die ihre Umgebung innerhalb der Hüllenfunktion an sich bindet, z.B. STATIC_OPTION bzw. die innere Klasse Item. Zusätzlich ist jede öffentliche Methode einer Instanz (new LinkedList) eine Closure ihrer Umgebung. In diesem Fall zählen dazu noch die privaten Variablen und Methoden der Instanz.

Das ist mein Ansatz zur Strukturierung meiner JavaScript-Klassen in Projekten. Wie ist Eurer? Arbeitet Ihr viel mit Closures? Welche Erfahrungen habt Ihr gemacht?

Im nächsten Blogpost möchte ich das Thema der Callbacks angehen und über eine wundervolle Möglichkeit schreiben, diese besser zu strukturieren. Bis dahin: Stay tuned!


  1. das zwar unvollständig ist, aber so im Browser oder in Node.JS ausprobiert werden kann
  2. Ich referenziere den this-Kontext mit self, weil ich dadurch einigen Problemen von JavaScript aus dem Weg gehen möchte. Jede Funktion wird mit einem this-Kontext aufgerufen, quasi ein zusätzliches Argument, das der Funktion automatisch übergeben wird. Das Problem sind die Callbacks, wie sie z.B. bei Ajax-Requests genutzt werden. Der this-Kontext der Callback-Funktion muss nicht zwangsläufig der von mir erwartete sein, oftmals ist er ein anderer. Das führt zu schwer auffindbaren Fehlern. Es gibt zwar andere Möglichkeiten, dieses Problem zu lösen. Aber durch meine durchgängige Nutzung der self-Variable gehe ich immer sicher, dass ich im richtigen Kontext arbeite.
  3. Übrigens, der Unterstrich an den Variablen _size oder _head soll auch optisch verdeutlichen, dass es eine private Variable ist. In einer Entwicklungsumgebung mit Auto-Vervollständigung ist es dadurch meist angenehmer, auf diese zuzugreifen

über den Autor

krone@pluspol.info'
Stefan ist leidenschaftlicher Gamer, Film- sowie Musikliebhaber und begeisterter Entwickler. Sein Interesse gilt den neuesten Technologien. Seine stete Unzufriedenheit mit dem Status Quo treibt ihn an, besser zu werden.



4 Kommentare für “JavaScript – Why Function matters. Teil 2”

  1. look@webinfluenza.de'

    Benno

    Hallo Stefan,
    einen schöne und interessante Beitragsserie hast du verfasst. Vielen Dank dafür! 🙂

    Im Abschnitt zu OOP-Closures sagst du “ Persönlich bin ich kein großer Fan der prototypischen Vererbung. […] Ein großer Nachteil ist das Fehlen privater […] Eigenschaften und Funktionen.“. Vielleicht ist es zu detailiert für einen Blogpost, aber JS bietet nativ doch einen private, privileged sowie public Scope. Ein Beispiel: http://jsfiddle.net/eynouh0w/

    Und mit einer anständigen API Definition lässt sich so sehr schön sauberer, wartbarer und testbareer Code erzeugen. Freue mich auf deine Gedanken dazu 🙂 Alles Gute!

    Antworten
    • krone@pluspol.info'

      Stefan von der Krone

      Hallo Benno,
      vielen Dank für deinen erhellenden Kommentar. Es freut mich sehr, dass dir der Post gefallen hat. Zu deinen Gedanken: Im Grunde habe ich ja am Beispiel der LinkedList genau das beschrieben, was du meinst. Wir beide meinen den Function-Scope, den wir geschickt zur Kapselung einsetzen. Dein jsfiddle ist auch ein schönes Beispiel dafür, wie man Scoping sowie Prototyping geschickt einsetzen kann. Das Prototyping hat auch einen Vorteil bzgl. der Performance, da zur Laufzeit für die neue Instanz ja nur die Änderungen zum Prototyp ausgeführt werden müssen. Der Prototyp selbst bleibt unverändert und wird lediglich kopiert. Aber genau hier liegt das Problem, sobald per Prototyping von einer Klasse geerbt werden soll, die selbst Variablen im privaten Scope hat. Das ganze habe ich dir mal im folgenden jsfiddle dargelegt: http://jsfiddle.net/thunderkrown/k78oh6vs/

      Die Problematik führt natürlich zu weiteren Diskussionen. So sind spezielle Bibliotheken für JavaScript-Klassen sicher hilfreich. Andererseits gibt es auch die interessante Ansicht unter den Theoretikern: Komposition über Vererbung. Das heißt vereinfacht ausgedrückt, dass die abgeleitete Klasse nicht direkt von der Basis-Klasse erbt, sondern diese einfach als private Instanz behält und mit ihr arbeitet. Ein Beispiel dafür findest du am Ende von meinem jsfiddle. Ein Vorteil ist, dass ich dadurch eine neue Klasse aus mehreren anderen „komponieren“ kann und das horizontal. Im Prototyping wäre das nur vertikal möglich. Andererseits hat das Prototyping den Vorteil, dass ich im Chrome natürlich die Vererbungshierarchie sehr gut nachvollziehen kann. Bei der Komposition wäre das nicht ohne Weiteres möglich.

      Hat alles seine Vor- und Nachteile 😀

      Antworten
      • look@webinfluenza.de'

        Benno

        Hey Stefan,

        danke für deine schöne Ausführung und das anschauliche Beispiel 🙂 Das Prinzip der „Komposition über Vererbung“ ist tatsächlich interessant und ich nutze auch in privaten Projekten zum Teil, aus den von dir genannten Vorteilen. Für kleinere, schnelle Arbeiten bin ich aber immer noch großer Freund der prototypischen Vererbung, da es halt relativ einfach geschrieben ist und super zu debuggen ist.

        Generell ist es wohl auch hier wieder situationsabhängig und eine Frage der persönlichen Vorliebe oder der vorgegebenen Konventionen. Aber es ist immer wieder schön Meinung von anderen über das Thema zu hören. Am Donnerstag, 20 Uhr, ist wahrscheinlich im BIC die „LeipzigJS – Leipziger JavaScript Usergroup“ (siehe XING). Ich werde wohl mal dort aufschlagen. Vielleicht hast du ja auch Lust. Ansonsten erstmal alles Gute und bis zum nächsten Kommentar 🙂

        Antworten

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.