--- layout: post title: "Closures in Javascript (und Scala)" date: 2012-08-03 21:37 comments: true categories: Javascript keywords: "closures, javascript, scala" --- Closures[^terminologie] sind meiner Meinung nach eines der interessantesten Sprachkonstrukte von Javascript. Sie erlauben sehr elegante Lösungen, die sonst nicht möglich wären. Was das konkret bedeutet, werde ich an einem Beispiel erläutern. Zunächst möchte ich aber erklären, was Closures sind. ## Was ist eine Closure? **Eine Closure beinhaltet eine Funktion und (auch nicht-lokale) Variablen, die innerhalb der Funktion referenziert werden.** Closures verändern die Lebensdauer von Variablen. Schauen wir uns dazu ein Beispiel an: ``` javascript var x = 0; function foo() { var y = 42; return x + y; } x = x + 1; ``` Wir sehen hier zwei Variablen, `x` und `y`. Im Hinblick auf die Sichtbarkeit unterscheiden sich die Variablen darin, dass `y` nur *innerhalb* der Funktion `foo` sichtbar ist. Was die Lebensdauer betrifft, so existiert `y` nur während `foo` ausgeführt wird. Sichtbarkeit und Lebensdauer für sich genommen sind keine schwierigen Konzepte. Javascript ist allerdings eine funktionale Sprache und da wird die Sache interessant. Javascript erlaubt es nämlich, Funktionen als Rückgabewert anderer Funktionen zu verwenden. Dazu erweitern wir das obige Beispiel. ``` javascript function makeFoo() { var x = 0; function foo() { var y = 41; x = x + 1; return x + y; } return foo; } var bar = makeFoo(); console.log(bar()); console.log(bar()); console.log(bar()); ``` In der Konsole erhält man folgende Ausgabe: ``` 42 43 44 ``` Das ist auf den ersten Blick überraschend, wenn wir davon ausgehen, dass lokale Variablen nur existieren, solange die Funktion, in der sie definiert wurden, ausgeführt wird. Die Variable `x` hingegen bleibt weiterhin innerhalb der Funktion `foo` bzw. `bar` sichtbar und behält zudem ihren Zustand, obwohl `makeFoo` vollständig abgearbeitet wurde. *`foo` wurde zusammen mit `x` in eine Closure gepackt*. ## Praktische Anwendung Das obige Beispiel ist konstruiert und in der Praxis kaum nützlich. Closures haben aber durchaus sinnvolle Anwendungen. Stellen wir uns einmal vor, wir wollten verschiedene Objekte mit einer eindeutigen Nummer (einer ID) versehen. Dazu wollen wir eine Funktion `generateId` definieren, die stets eine andere Zahl zurückliefert. Der Einfachheit halber zählen wir von 0 aufwärts. Wir haben mehrere Möglichkeiten dieses Problem zu lösen. ### Möglichkeit 1: Globaler Zähler ``` javascript var counter = 0; function generateId() { var id = counter; counter = counter + 1; return id; } var obj = { id: generateId() } ``` Ich halte diese Lösung für nicht sehr sinnvoll. `counter` ist eine globale Variable. D.h. wir verschmutzen hier den globalen Namensraum mit einer Variable, die nur für eine einzige Funktion benötigt wird. Außerdem kann die Variable praktisch an jeder Stelle im Programm versehentlich geändert werden. Und es wird überhaupt nicht klar, dass counter` und `generateId` zusammengehören. ### Möglichkeit 2: Zähler und Funktion in einem Objekt ``` javascript var idGenerator = { counter: 0, generateId: function() { var id = this.counter; this.counter = this.counter + 1; return id; } }; var obj = { id: idGenerator.generateId() } ``` Diese Lösung ist schon etwas besser, in der Hinsicht, dass wir auf eine globale Variable `counter` verzichten. Auch wird der Zusammenhang von `counter` und `generateId` deutlicher. Allerdings ist diese Variante unhandlich in der Verwendung (`idGenerator.generateId()`). Außerdem kann auch hier `counter` an anderer Stelle im Programm geändert werden, obwohl die Variable einzig und allein von der Funktion `generateId` manipuliert werden sollte. ### Möglichkeit 3: Closure ``` javascript var generateId = (function() { var counter = 0; return function() { var id = counter; counter = counter + 1; return id; }; })(); var obj = { id: generateId() } ``` Ich halte diese Lösung für die eleganteste. Der Zusammenhang von `counter` und `generateId` wird deutlich und der Zähler ist außerhalb der Funktion überhaupt nicht sichtbar. ## Anhang: Das Beispiel in Scala Closures gibt es nicht nur in Javascript, sondern in wohl jeder funktionalen Programmiersprache. Ich habe mich kürzlich im Rahmen einer Vorlesung mit Scala beschäftigen dürfen, daher hier das obige Beispiel in Scala: ``` scala val generateId = (() => { var counter = 0 () => { var id = counter; counter = counter + 1; id } }).apply() ``` [^terminologie]: Kurz zur Terminologie: Das deutsche Wort für „function closure“ ist wohl „Funktionsabschluss“. Allerdings hat man wenig Glück, wenn man danach googlet. Mir scheint der Begriff nicht sehr gebräuchlich zu sein, also bleibe ich bei der englischen Bezeichnung.