vorige Präsentation: Funktionen und Closures | zurück zum Buch-Kapitel [esc] | Nächste Präsentation Stil + Tipps
Wie kann man Javascript-Code in größere Einheiten organisieren? Wo doch die Sprache keine Unterstütztung für Namespaces oder Kapselung bietet?
Eine Lösung für diese Fragestellung ist der Modul-Pattern, hier beschrieben nach Stefanov(2010): Javascript Patterns, Kapitel 5. Siehe auch Osmani(2012): Learning JavaScript Design Patterns.
Häuft werden in einer Webseite Javascript-Programm aus verschiedenen Quellen kombiniert. Die Webseite enthält z.B.
Mit ein bisschen Copy-und-Paste kann man die verschiedenen Programme schnell in die eigene Webseite einbauen. All diese Programme laufen dann im selben Javascript Interpreter ab, und benutzen einen gemeinsamen globalen Namensraum.
Um einen Namensraum zu imitieren kann man ein Objekt in Javascript verwenden.
Die linke Version erzeugt 5 globale Namen. Oder, um genauer zu sein: sie
erzeugt 3 Eigenschaften und 2 Methoden des window
-Objekts. Würde ein
anderes Programm ebenfalls ein Funktion f()
definieren, so würde
die spätere Definition erhalten bleiben.
In der rechten Version wird nur ein globaler Name angelegt: APP
.
Alle weiteren Namen sind dann in diesem Objekt versteckt. Würde
ein anderes Programm in der Webseite auch eine Funktion f()
definieren
dann wäre das kein Problem mehr.
// globale Variabeln var KONSTANTE = 3.141; var variable = 3; function Ding(){ return this; } function f(x){ return 2*x; } var objekt = new Ding();
// ein Namensraum-Objekt var APP = {} APP.KONSTANTE = 3.141; APP.variable = 3; APP.Ding = function() { return this; } APP.f = function(x) { return 2*x; } APP.objekt = new APP.Ding();
Wenn man modernes Javascript (z.B. ES6) oder ES5 mit “use strict” verwendet, dann erhält man Fehlermeldungen beim Zugriff auf nicht deklarierte Variablen.
Das Objekt als Namensraum kann das nicht bieten: ein nicht existierendes Attribut des Objekt
liefert einfach den Wert undefined
, aber keinen Fehler:
Namensräume können auch verschachtelt werden:
var GAME = GAME || {}; GAME.Player = ... GAME.Master = ...
Die erste Zeile enthält eine Vorsichtsmaßnahme: Falls
GAME
schon definiert wäre, dann wird die alten Definition
nicht überschrieben. Dabei macht man sich die
Kurzschulssauswertung
des Oder-Operators zu nutze.
Folgender Code zeigt eine alternative Schreibweise für diese Zuweisung:
var GAME = GAME || {};
var GAME; if( GAME ) { // GAME = GAME; } else { GAME = {}; }
Eine andere Methode um den globalen Namensraum sauber zu halten sind die sogenannten “sofort augewerteten Funktionen” (“immediately invoked funktion” oder “immediate function”).
Dabei wird eine Funktion definiert und sofort - und nur einmal - aufgerufen.
Nur der Rückgabewert wird ein einer globalen Variable g
gespeichert.
Beachten sie dabei die Klammern rund um die Funktions-Definition:
var g = (function(){ return 42; })();
Hier eine komplexere Version. Die vielen Variablen und Funktionen die innerhalb der sofort ausgewertete Funktion definiert sind, bleiben unsichtbar. Sie sind “von aussen” nicht zugänglich.
var g = (function(){ var a,b,c; function d(x) { return 2*x; } function Ding(v) { this.value = v; } a = 10; b = d( a ); c = new Ding(b); return a; })();
Namensräume und sofort augewertete Funktionen werden verwendet um sogenannte Module zu bauen. Das Modul bündelt alle Namen unter einem Namensraum und bietet die Möglichkeit von privaten und öffentlichen Eigenschaften und Funktionen.
In diesem Beispiel ist das Modul ein Objekt:
var APP = (function(){ var a,b,f; // private var c,d,g; // öffentlich f = function() { // private Funktion }; g = function() { // öffentliche Funktion }; return { c: c, d: d, g: g }; })();
vorige Präsentation: Funktionen und Closures | zurück zum Buch-Kapitel [esc] | Nächste Präsentation Stil + Tipps
/
#