Seminararbeit im Kurs 1908
OOP-Sprachen und -Konzepte
Thema: Praxisorientierte Nutzung von
Prototypen in JavaScript am Bei...
Seminararbeit zum Kurs 1908 - Thema: JavaScript ii
Inhaltsverzeichnis
1 Einleitung 1
2 Prototypenbasierte Programmierung 1...
Seminararbeit zum Kurs 1908 - Thema: JavaScript 1
1 Einleitung
Diese Seminararbeit entstand im Rahmen des Kurses
”
1908 - ...
Seminararbeit zum Kurs 1908 - Thema: JavaScript 2
2.2 Prototypen in der objektorientierten Programmierung
Wie Objekte in d...
Seminararbeit zum Kurs 1908 - Thema: JavaScript 3
2.3 Eigenschaften protoypenbasierter Programmiersprachen
Bevor im n¨achs...
Seminararbeit zum Kurs 1908 - Thema: JavaScript 4
Dieser Slot beihnaltet eine Referenz auf den Prototypen des Objektes, al...
Seminararbeit zum Kurs 1908 - Thema: JavaScript 5
Abbildung 2: Schematische Darstellung der Delegation,
Quelle: Eigene Dar...
Seminararbeit zum Kurs 1908 - Thema: JavaScript 6
Kombination mit klassischer Vererbung. Objekte k¨onnen in einem Objektbr...
Seminararbeit zum Kurs 1908 - Thema: JavaScript 7
3.1.2 JavaScript als missverstandene Sprache
Douglas Crockford, der mit ...
Seminararbeit zum Kurs 1908 - Thema: JavaScript 8
orientiert sich dabei an dem bereits beschrieben Konzept der Slots, die ...
Seminararbeit zum Kurs 1908 - Thema: JavaScript 9
Listing 2: Objekterzeugung mittels Konstruktoraufruf
1 function Elephant...
Seminararbeit zum Kurs 1908 - Thema: JavaScript 10
3.2.3 Klonung und Erweiterung
In Abschnitt 2.3.1 haben wir bereits die ...
Seminararbeit zum Kurs 1908 - Thema: JavaScript 11
3 Object.getPrototypeOf ( Object.prototype ) === null; // true
3.3.2 [[...
Seminararbeit zum Kurs 1908 - Thema: JavaScript 12
Abbildung 4: Prototypen in JavaScript, Quelle: Eigene
Darstellung
Deleg...
Seminararbeit zum Kurs 1908 - Thema: JavaScript 13
typen werden zwei konkrete Elefanten erzeugt.
In den Zeilen 13-15 wird ...
Seminararbeit zum Kurs 1908 - Thema: JavaScript 14
Es ist allerdings leicht zu erkennen, dass sich mit dem Ansatz der Dele...
Seminararbeit zum Kurs 1908 - Thema: JavaScript 15
Abbildung 6: Pseudo-klassenbasierte Vererbung, Quelle:
Eigene Darstellu...
Seminararbeit zum Kurs 1908 - Thema: JavaScript 16
3 function F() {}
4 F.prototype = o;
5 return new F();
6 };
7 }
8
9 new...
Seminararbeit zum Kurs 1908 - Thema: JavaScript 17
Klonung eines existierenden Objektes. In den Zeile 10-23 erfolgt eine E...
Seminararbeit zum Kurs 1908 - Thema: JavaScript 18
15 var clyde = new Elephant("Clyde");
16 clyde.name === "Clyde"; // tru...
Seminararbeit zum Kurs 1908 - Thema: JavaScript 19
der Praxis. Der Schwerpunkt liegt hierbei auf der Untersuchung der weit...
Seminararbeit zum Kurs 1908 - Thema: JavaScript 20
7 var httpRequest = new XMLHttpRequest ()
8 httpRequest.onreadystatecha...
Seminararbeit zum Kurs 1908 - Thema: JavaScript 21
Abbildung 8: Verbreitung verschiedener JavaScript
Bibliotheken [Stand 1...
Seminararbeit zum Kurs 1908 - Thema: JavaScript 22
• Browserkompatibilit¨at: Die Gew¨ahrleistung der Browserkompatibilit¨a...
Seminararbeit zum Kurs 1908 - Thema: JavaScript 23
Listing 13: Erstmalige Erzeugung des jQuery-Objektes
1 (function( globa...
Seminararbeit zum Kurs 1908 - Thema: JavaScript 24
4.2.2 Verwendung von Prototypen
Bei jQuery.fn handelt es sich lediglich...
Seminararbeit zum Kurs 1908 - Thema: JavaScript 25
• Callback-Funktionen: Ereignisse und ihre Behandlung spielen in JavaSc...
Seminararbeit zum Kurs 1908 - Thema: JavaScript 26
dieser Elemente wird nun ein neuer Event-Listener zugewiesen, wobei die...
Seminararbeit zum Kurs 1908 - Thema: JavaScript 27
Hauptdom¨ane, dem Browser, entfernt, denn durch die flexible Paarung aus...
Seminararbeit zum Kurs 1908 - Thema: JavaScript 28
[7] G¨unther Blaschek. Object-Oriented Programming with Prototypes. 199...
Seminararbeit zum Kurs 1908 - Thema: JavaScript 29
[25] Draft ECMA-262 6th Edition. 2014. url: http://mzl.la/1rTkdmK (besu...
Nächste SlideShare
Wird geladen in …5
×

Praxisorientierte Nutzung von Prototypen in JavaScript am Beispiel von jQuery

372 Aufrufe

Veröffentlicht am

Diese Seminararbeit behandelt in fünf Kapiteln die prototypenbasierte Programmierung in JavaScript. Der Schwerpunkt liegt neben der theoretischen Einordnung des Begriffs "Prototyp" auf dem praktischen Einsatz dieses Programmierparadigmas zur Realisierung bekannter Eigenschaften der klassenbasierten Objektorientierung wie z.B. Vererbung.
Die konkrete Untersuchung der Praxistauglichkeit erfolgt am Beispiel der bekannten Bibliothek jQuery.

Veröffentlicht in: Wissenschaft
0 Kommentare
0 Gefällt mir
Statistik
Notizen
  • Als Erste(r) kommentieren

  • Gehören Sie zu den Ersten, denen das gefällt!

Keine Downloads
Aufrufe
Aufrufe insgesamt
372
Auf SlideShare
0
Aus Einbettungen
0
Anzahl an Einbettungen
2
Aktionen
Geteilt
0
Downloads
0
Kommentare
0
Gefällt mir
0
Einbettungen 0
Keine Einbettungen

Keine Notizen für die Folie

Praxisorientierte Nutzung von Prototypen in JavaScript am Beispiel von jQuery

  1. 1. Seminararbeit im Kurs 1908 OOP-Sprachen und -Konzepte Thema: Praxisorientierte Nutzung von Prototypen in JavaScript am Beispiel von jQuery Autor: Robert Schweda Matrikelnummer: 8802440 Fernuniversit¨at Hagen
  2. 2. Seminararbeit zum Kurs 1908 - Thema: JavaScript ii Inhaltsverzeichnis 1 Einleitung 1 2 Prototypenbasierte Programmierung 1 2.1 Historische Einordnung . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 2.2 Prototypen in der objektorientierten Programmierung . . . . . . . . . . 2 2.3 Eigenschaften protoypenbasierter Programmiersprachen . . . . . . . . . 3 2.3.1 Fehlen von Klassen und Konstruktoren . . . . . . . . . . . . . . 3 2.3.2 Slots und Parent-Slot . . . . . . . . . . . . . . . . . . . . . . . . 3 2.3.3 Delegation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 2.3.4 Vielfalt prototypenbasierter Programmiersprachen . . . . . . . . 5 3 Prototypen in JavaScript 6 3.1 Geschichte JavaScripts . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 3.1.1 ECMAScript . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 3.1.2 JavaScript als missverstandene Sprache . . . . . . . . . . . . . . 7 3.1.3 JavaScript heute . . . . . . . . . . . . . . . . . . . . . . . . . . 7 3.2 Objekte in JavaScript . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 3.2.1 Objektliterale . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 3.2.2 Konstruktoren . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 3.2.3 Klonung und Erweiterung . . . . . . . . . . . . . . . . . . . . . 10 3.3 Prototype-Eigenschaft . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 3.3.1 Object.prototype . . . . . . . . . . . . . . . . . . . . . . . . . . 10 3.3.2 [[Prototype]] und Konstruktoren . . . . . . . . . . . . . . . . . . 11 3.4 Delegation in JavaScript . . . . . . . . . . . . . . . . . . . . . . . . . . 11 3.5 Vererbung in JavaScript . . . . . . . . . . . . . . . . . . . . . . . . . . 13 3.5.1 Pseudo-klassenbasierte Vererbung . . . . . . . . . . . . . . . . . 14 3.5.2 Prototypenbasierte Vererbung . . . . . . . . . . . . . . . . . . . 15 3.5.3 Mischformen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 3.5.4 Mixins als Alternative . . . . . . . . . . . . . . . . . . . . . . . 18 4 JavaScript in der Praxis 18 4.1 Das jQuery-Projekt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 4.2 Untersuchung ausgew¨ahlter Quelltextpassagen . . . . . . . . . . . . . . 22 4.2.1 Initialisierung des jQuery-Objekts . . . . . . . . . . . . . . . . . 22 4.2.2 Verwendung von Prototypen . . . . . . . . . . . . . . . . . . . . 24 4.2.3 Weitere Besonderheiten im Entwurf . . . . . . . . . . . . . . . . 24 4.2.4 Praxisbeispiel . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 5 Zuk¨unftige Entwicklung und Fazit 26 6 Anhang 27
  3. 3. Seminararbeit zum Kurs 1908 - Thema: JavaScript 1 1 Einleitung Diese Seminararbeit entstand im Rahmen des Kurses ” 1908 - OOP-Sprachen und - Konzepte“ an der Fernuniversit¨at Hagen, und besch¨aftigt sich mit der prototypenba- sierten Programmiersprache JavaScript. Nach einer kurzen theoretischen Betrachtung des Prototypenbegri↵s und der prototypenbasierten Programmierung im Allgemeinen, befasst sich der Hauptteil der Arbeit in den Kapiteln 3 und 4 mit einer konkreten Implementierung einer solchen Sprache in Form von JavaScript und ihrem praktischen Einsatz in Form der jQuery Bibliothek. 2 Prototypenbasierte Programmierung Bevor das Themengebiet der prototypenbasierten Programmierung genauer untersucht wird, soll zun¨achst die Entstehung des Begri↵s ” Prototyp“ vorgestellt werden. Inter- essierte Leser finden hierzu in [1] eine ausf¨uhrliche Ausarbeitung, die im n¨achsten Ab- schnitt kurz zusammengefasst wird. 2.1 Historische Einordnung Die objektorientierte Programmierung ist eng mit dem Begri↵ der Klasse verkn¨upft. Der Ursprung der Kategorisierung und des Klassenbegri↵s selbst findet sich bereits in der Antike bei Platon wieder. Platon unterscheidet zwischen zwei Arten von Objekten, zum einen Objekte, die Eigenschaften von Dingen beschreiben (sog. Ideen, Formen) und zum anderen real existierende Objekte, die diese Eigenschaften vereinen. Mit die- sem Sachverhalt beschreibt der griechische Philosoph im Wesentlichen die Beziehung zwischen Klassen und ihren Instanzen [2]. Sein Sch¨uler Aristoteles formulierte mit der Definitionsregel ” genus proximum et dif- ferentia specifica“ die Prinzipien der Generalisierung und Spezialisierung, wie man sie auch heute in der objektorientierten Programmierung wiederfindet. Nach Aristoteles wird ein neuer Begri↵ durch einen Oberbergri↵ (genus proximum) und einer Menge von Eigenschaften, die ihn von diesen abgrenzen, beschrieben (di↵erentia specifica) [3]. Kritik an dieser Form der Kategorisierung wurde im 20. Jahrhundert durch den Philo- sophen Ludwig Wittgenstein ge¨außert. Wittgenstein stellte fest, dass es gewisse Dinge gibt, die nicht klar kategorisiert werden k¨onnen. Als Beispiel bringt er den allgemeinen Begri↵ des ” Spiels“. Spiele verf¨ugen ¨uber eine Menge von Verwandtschaften, die Witt- genstein als Familien¨ahnlichkeiten bezeichnet. Jedes individuelle Spiel verf¨ugt ¨uber Eigenschaften, durch die es sich als Spiel auszeichnet, es existiert allerdings keine ge- meinsame Eigenschaft, ¨uber die alle Spiele verf¨ugen [4, S. 56-68]. In den Siebzigerjahren setzte Elenoar Rosch die Forschung auf dem Gebiet der Fami- lien¨ahnlichkeiten fort. Sie stellte fest, dass es Entit¨aten gibt, die eine Klasse besser repr¨asentieren als andere. Ein Singvogel ist beispielsweise ein typischerer Vertreter der Kategorie Vogel als ein Pinguin oder ein Huhn. Diese klassenspezifischen Vertreter bezeichnete sie als Prototypen [5].
  4. 4. Seminararbeit zum Kurs 1908 - Thema: JavaScript 2 2.2 Prototypen in der objektorientierten Programmierung Wie Objekte in der realen Welt beschrieben werden, wirkt sich unmittelbar auf den Ent- wurf von Programmiersprachen aus, die mit diesen Objekten arbeiten m¨ussen. Wie bei der Kategorisierung anhand von Klassen in der Philosophie, existiert auch im Bereich der klassenbasierten Programmierung Kritik an diesem Konzept. Die beiden wesentli- chen Punkte dabei lauten nach [6] und [7, S. 92]: • Die Erstellung einer Klassenhierarchie ist ein kreativer Vorgang, der zu vielen verschiedenen L¨osungen f¨uhren kann. Dabei kann es sogar sein, dass eine L¨osung, die sich in der Theorie als besonders elegant erweist, nicht praktikabel ist. • Der Begri↵ der Klasse ist nicht eindeutig und repr¨asentiert unterschiedliche Kon- zepte. Klassen k¨onnen mathematisch als Mengen interpretiert werden. Zugleich dienen sie der Beschreibung ihrer Instanzen und bieten außerdem Mechanismen zur Erzeugung dieser konkreten Vertreter. In den achtziger Jahren befassten sich Wissenschaftler damit Alternativen zur klas- senbasierten Programmierung zu erforschen und fokussierten sich dabei unter anderem auf die Verwendung von Prototypen. Je nach Forschungsschwerpunkt variiert die Defi- nition des Begri↵s in den unterschiedlichen Ver¨o↵entlichungen. Anlehnend an [7, S. 92] wird in dieser Arbeit ein Prototyp als ein bereits vorgefertigtes, strukturiertes Objekt mit Eigenschaften und einem Verhalten aufgefasst, das bei Bedarf als Vorlage f¨ur die Erstellung eines neuen Objektes herangezogen werden kann. Ein anschauliches Beispiel f¨ur diese Definition bietet Lieberman in [8]: Nehmen wir an, wir kennen einen ganz bestimmten Elefanten namens Clyde (weil wir z.B. Tierpfle- ger im ¨ortlichen Zoo sind), dann k¨onnen wir unser Wissen ¨uber Clyde dazu nutzen, Aussagen ¨uber einen anderen Elefanten, namentlich Fred, zu tre↵en. Wir k¨onnen bei- spielsweise sagen, dass Fred grau ist und vier Beine hat.1 Die Vorteile, die sich aus der Verwendung von Prototypen statt Klassen ergeben, lauten nach [9]: • Es handelt sich um einen nat¨urlicheren Ansatz, da man bei der L¨osung von Problemen h¨aufig versucht, von einem konkreten Fall ausgehend eine abstrakte L¨osung zu finden. Die Nutzung von Prototypen spiegelt diese Vorgehensweise auf der Ebene der Programmierung wider. • Eine flexiblere Nutzung von Objekten wird erm¨oglicht, da ¨Anderungen an ein- zelnen Objekten nicht alle anderen Instanzen dieses Typs betre↵en. • Klassen werden oft als komplex und einschr¨ankend empfunden. Beispielsweise werden in der Programmierung von grafischen Oberfl¨achen h¨aufig gleichartige Elemente ben¨otigt, die sich nur marginal (z.B. in der Eventverarbeitung) von- einander unterscheiden. Trotz der geringen Di↵erenzen m¨usste f¨ur jedes dieser Elemente gleich eine neue Klasse definiert werden. 1 Die Tatsache, das Fred nicht grau ist oder ¨uber eine unnat¨urliche Anzahl an Beinen verf¨ugen k¨onnte, ignorieren wir an dieser Stelle und verweisen auf die Abschnitte 2.3.3 und 3.4.
  5. 5. Seminararbeit zum Kurs 1908 - Thema: JavaScript 3 2.3 Eigenschaften protoypenbasierter Programmiersprachen Bevor im n¨achsten Kapitel mit JavaScript eine Implementierung einer prototypenba- sierten Sprache untersucht wird, sollen in diesem der Teil Arbeit zun¨achst typische Ei- genschaften einer solchen Sprache vorgestellt werden. Dabei ist zu beachten, dass nicht jede Sprachimplementierung zwingend ¨uber alle vorgestellten Merkmale verf¨ugen muss. Die erste prototypenbasierte Programmiersprache ¨uberhaupt war Self, die 1986 von David Unger und Randall B. Smith entwickelt wurde, und die nachfolgend erl¨auterten Spracheigenschaften allesamt implementierte [10]. 2.3.1 Fehlen von Klassen und Konstruktoren Charakteristisch f¨ur die prototypenbasierte Programmierung ist das Fehlen von Klas- sen, das allerdings nicht automatisch den Wegfall aller klassenbasierter Konzepte, wie z.B. der Vererbung, zur Folge hat. Durch den hohen Grad an Flexibilit¨at der proto- typenbasierten Sprachen k¨onnen diese Mechanismen h¨aufig simuliert werden. In Ab- schnitt 3.5 werden beispielsweise gleich mehrere Varianten zur Realisierung von Verer- bung in der Sprache JavaScript vorgestellt. Mit dem Begri↵ der Klasse f¨allt auch die M¨oglichkeit der Erzeugung von Instanzen durch Konstruktoren weg. Es stellt sich nun die Frage, wie konkrete Objekte stattdes- sen erzeugt werden k¨onnen? Hierzu benennt die Literatur verschiedene M¨oglichkeiten [10, 7, S. 84 ↵.]: • Klonung und Erweiterung existierender Objekte: Bei der Erzeugung eines neuen Objektes durch Klonung wird ein bereits existierendes Objekt als Vorlage f¨ur ein neues Objekt herangezogen. Es wird neben dem Verhalten auch der Zu- stand des Ursprungsobjektes (parent) auf den Klon (child) ¨ubertragen. Eine Spezialform des Klonens stellt die Erweiterung dar. Sie erm¨oglicht es, ein konkretes Objekt durch die Benennung eines Ursprungsobjektes und einer Menge von weiteren Eigenschaften und Unterschieden zu erstellen. • Erzeugung ex nihilo: Bevor Objekte geklont oder erweitert werden k¨onnen, muss allerdings mindestens ein konkretes Objekt existieren. Dies kann bereits durch die Laufzeitumgebung der Sprache bereitgestellt oder ex nihilo vom Pro- grammierer erstellt werden. Unter Letzterem versteht man typischerweise eine Beschreibung eines Objektes durch Benennung und Belegung seiner Eigenschaf- ten und seines Verhaltens an Ort und Stelle der Verwendung. 2.3.2 Slots und Parent-Slot Objekte werden in prototypenbasierten Sprachen als eine Menge von sog. Slots auf- gefasst.2 Ein Slot meint dabei ein einfaches Schl¨ussel-Wert-Paar (key-value-pair), ent- spricht also der Datenstruktur der Map. Der Zugri↵ auf einen Wert, der sowohl Daten (Zustand des Objekts) als auch Funktionen (Verhalten des Objekts) beinhalten kann, erfolgt ¨uber einen Schl¨ussel [7, S. 96 f.]. In einigen Sprachen verf¨ugen Objekte ¨uber einen speziellen Slot, den sog. Parent-Slot. 2 Der Begri↵ des Slots stammt aus dem Bereich der k¨unstlichen Intelligenz und bezeichnet einfach eine Menge von Daten, die zu einer bestimmten Situation (frame) geh¨oren. Siehe [11] f¨ur weitere Informationen.
  6. 6. Seminararbeit zum Kurs 1908 - Thema: JavaScript 4 Dieser Slot beihnaltet eine Referenz auf den Prototypen des Objektes, also das Objekt, das beim Klonen also Vorlage diente. Der Parent-Slot spielt eine entscheidende Rolle Abbildung 1: Schematische Darstellung eines Objektes mit n+1 Slots, Quelle: Eigene Darstellung bei der Realiserung der sog. Delegation, die im n¨achsten Abschnitt theoretisch erl¨autert und in Abschnitt 3.4 an praktischen Beispielen in der Programmiersprache JavaScript demonstriert wird [10]. 2.3.3 Delegation In der klassenbasierten Programmierung entsprechen Klassen Baupl¨anen f¨ur Objekte. Eine Klasse definiert dabei eine Menge von Attributen, ¨uber die jede ihrer Instanzen verf¨ugt. Die Belegung dieser Attribute mit konkreten Werten geschieht individuell auf der Ebene der Instanzen d.h. jede Instanz verf¨ugt ¨uber ihren eigenen Zustand.3 Klassen definieren dar¨uber hinaus das Verhalten ihrer zuk¨unftigen Instanzen. ¨An- derungen am Verhalten der Klasse haben zur Folge, dass sich das Verhalten aller kon- kreten Objekte dieser Klasse ¨andert. M¨ochte man ein Objekt erzeugen, dass sich durch zus¨atzliche Attribute oder ein besonderes Verhalten auszeichnet, so muss eine Speziali- sierung in Form einer Subklasse erzeugt werden, die alle Eigenschaften der Basisklasse erbt und um zus¨atzliche Eigenschaften erweitert wird [8, 7, S. 94 ↵.]. Eine Alternative zur klassenbasierten Vererbung bieten prototypenbasierte Sprachen in Form der sog. Delegation. Erh¨alt ein Objekt in einer Programmiersprache, die De- legation unterst¨utzt, eine Nachricht wie z.B. den Abruf einer Eigenschaft, so versucht es zun¨achst selbst diese Nachricht zu beantworten. Ist dies nicht m¨oglich, so wird die Nachricht an das Objekt im Parent-Slot des empfangenden Objektes weitergeleitet. Dieser Vorgang kann nun solange wiederholt werden bis die Eigenschaft in einem der Delegaten gefunden wird, oder das Ende der Kette erreicht wird. M¨ochte nun ein Kind- Objekt einen Attributwert ¨andern, der von seinem Prototypen-Objekt stammt, reicht es aus diesen Wert lokal im Kind-Objekt zu setzen. Dieser Sachverhalt soll noch einmal in Abbildung 2 verdeutlicht werden. Clyde ist der Prototyp von Fred, da Freds Parent-Slot ¨uber eine Referenz auf das Objekt von Clyde verf¨ugt. Wird nun Fred nach der Anzahl seiner Stoßz¨ahne gefragt, so wird die Anfrage implizit an Clyde delegiert, der als Prototyp von Fred mit ” 2“ antwortet. Wird Fred wiederum nach seinem Namen gefragt, muss die Anfrage nicht weitergeleitet werden, da er selbst ¨uber einen Slot mit entsprechendem Schl¨ussel verf¨ugt. 3 Mit Hilfe von statischen Variablen kann in den meisten klassenbasierten Sprachen auch ein gemein- samer Zustand erzeugt werden.
  7. 7. Seminararbeit zum Kurs 1908 - Thema: JavaScript 5 Abbildung 2: Schematische Darstellung der Delegation, Quelle: Eigene Darstellung In Abschnitt 3.4 wird gezeigt, wie der Mechanismus der Delegation in JavaScript ge- nutzt werden kann, um Vererbung zu simulieren. Der umgekehrte Fall ist allerdings nicht m¨oglich. Dies liegt an den unterschiedlichen Arten, wie in den prototypen- und klassenbasierten Sprachen mit der Selbstreferenz self bzw. this umgegangen wird. In klassenbasierten Sprachen bezieht sich die Variable self immer auf den Empf¨anger Abbildung 3: Forwarding vs. Delegation, Quelle: http://bit.ly/1yGzr2y eines Methodenaufrufes. Man nennt diese Art von Aufruf auch Forwarding.4 Es ist also nicht m¨oglich Methoden so aufzurufen, dass self ein anderes Objekt referenziert. Die Delegation der prototypenbasierten Sprachen erm¨oglicht dies hingegen, da die Variable self in diesem Fall nicht den Aufgerufenen (Client), sondern den Aufrufer (Server) referenziert. Neben dem Zustand kann so auch das Verhalten des Prototypen wieder- verwendet werden [8]. 2.3.4 Vielfalt prototypenbasierter Programmiersprachen Am Ende dieses Kapitels soll kurz anhand der beiden Sprachen Kevo und Omega verdeutlicht werden, dass die vorgestellten Eigenschaften nicht notwendigerweise f¨ur alle Implementierungen prototypenbasierter Sprachen gelten. • Kevo: Die Programmiersprache Kevo verf¨ugt weder ¨uber einen Parent-Slot noch den Mechanismus der Delegation. Wird ein Objekt geklont, so wird eine un- abh¨angige Kopie, die in keinerlei Beziehung zum Parent steht, erzeugt. Es steht dem Entwickler danach frei beliebige ¨Anderungen an dem neu erzeugten Objekt durchzuf¨uhren. Objekte k¨onnen zudem in Gruppen zusammengefasst werden, die ebenfalls durch sog. modifications ver¨andert werden k¨onnen [7, S. 100 ↵.]. • Omega: Beim Entwurf der Sprache Omega wurde Wert auf Typsicherheit ge- legt. Man entschied sich daher f¨ur die Nutzung einer statischen Typpr¨ufung in 4 In der klassenbasierten Programmierung werden die Begri↵e Delegation und Forwarding h¨aufig synonym verwendet. Gemeint ist meist Letzeres, siehe [12, S. 116 f.].
  8. 8. Seminararbeit zum Kurs 1908 - Thema: JavaScript 6 Kombination mit klassischer Vererbung. Objekte k¨onnen in einem Objektbrow- ser erzeugt und von bereits existierenden Objekten abgeleitet werden. Prototypen dienen in Omega daher zus¨atzlich der Definition von Interfaces, da abgeleitete Objekte sicherstellen m¨ussen, dass das Interface des Prototypen eingehalten wird [13, 7, S. 104]. 3 Prototypen in JavaScript In diesem Kapitel wird die konkrete Implementierung einer prototypenbasierten Pro- grammiersprache anhand der weit verbreiteten Sprache JavaScript vorgestellt. Im ers- ten Teil wird die Geschichte JavaScripts kurz vorgestellt. Nach einem kurzen Exkurs zum Objektbegri↵ besch¨aftigt sich der Hauptteil dieses Kapitels mit dem Konzept des Prototypen, sowie der Delegation und Vererbung. 3.1 Geschichte JavaScripts Die Programmiersprache JavaScript wurde im Jahr 1995 von Brendan Eich, einem damaligen Mitarbeiter des Unternehmens Netscape Communications, erfunden und umgesetzt. Eine Besonderheit dieser Sprache ist die Tatsache, dass Eich sie in in weni- gen Tagen entwickelt hat, und sie dennoch bis heute weitergenutzt wird [14]. Eich bediente sich dabei an Sprachkonzepten, die er f¨ur besonders n¨utzlich empfand. Anders als der Name der Sprache vermuten l¨asst, wurde er nicht durch die Sprache Java, sondern durch die prototypenbasierte Sprache Self und die funktionalen Sprachen Scheme bzw. Lisp inspiriert. Seine Implementierung fand im selben Jahr Einzug in den Netscape Navigator,5 und wurde bereits ein Jahr sp¨ater von Microsoft kopiert und als JScript im Internet Explorer angeboten [15, S. 1, 14]. 3.1.1 ECMAScript Die alternativen Implementierungen der Sprache f¨uhrten zum sog. Browserkrieg und der damit verbundenen Problematik der konkurrierenden DHTML-Implementierungen. Da jeder Browser ¨uber eigene Features und Interfaces verf¨ugte, mussten Entwickler h¨aufig browser-spezifischen Quelltext schreiben. Um den Inkompatibilit¨aten und der resultierenden Doppelbelastung entgegenzuwirken, meldete der Microsoft Konzern be- reits 1996 eine Spezifikation der Sprache beim European Computer Manufacturers Association (ECMA) an. Rechtsstreitigkeiten f¨uhrten dazu, dass der verabschiedete Standard weder Java- noch J-, sondern ECMAScript6 hieß [15, S. 2]. Die relevanten Versionen von ECMAScript sind die Versionen 3 und 5, die 1999 und 2009 verabschiedet wurden, und die Sprache um wichtige Features wie z.B. Regular Expressions und den Strict mode erweitert haben [16]. In diesem Dokument wird der Begri↵ JavaScript synonym zur Implementierung der ECMAScript Version 5.1 verwendet. Sollte eine andere Version des Standards gemeint sein, so wird an der jeweiligen Stelle explizit darauf hingewiesen. 5 Damals noch unter dem Namen LiveScript. 6 Laut Brendan Eich war die Einigung auf diesen Namen noch tragischer als die tr¨ugerische Bezeich- nung JavaScript, da ECMA nach einer Hautkrankeit klinge.
  9. 9. Seminararbeit zum Kurs 1908 - Thema: JavaScript 7 3.1.2 JavaScript als missverstandene Sprache Douglas Crockford, der mit seinem Werk ” JavaScript - The Good Parts“, maßgeblich an der Verbesserung von JavaScripts Ruf beteiligt war, bezeichnet unter [17] JavaScript als die am meisten missverstandenste Programmiersprache. ” Am meisten“ bezeichnet dabei nicht nur die Anzahl der Missverst¨andnisse selbst, sondern auch die große Menge an Entwicklern, die die Sprache missverstehen. Letzeres liegt vor allem an der großen Verbreitung der Sprache, die von vielen modernen Browsern interpretiert werden kann. Die beiden wichtigsten Missverst¨andnisse lauten: • Namensgebung: Der Name der Programmiersprache l¨asst auf eine Verwandt- schaft mit der objektorientierten und vor allem klassenbasierten Sprache Ja- va schließen. Leider haben die beiden Sprachen außer der C-¨ahnlichen Syntax keine Gemeinsamkeiten. Die Bezeichnung JavaScript ist ein reiner Marketing- Schachzug gewesen, der die Sprache popul¨arer machen sollte [14]. Die Tatsache, dass der Sprachstandard ECMAScript heißt und es diverse Implementierungen gibt (JavaScript, ActionScript, JScript) tat ihr Restliches, um zur allgemeinen Verwirrung beizutragen. • Unbekannte Konzepte: Das Konzept der funktionalen Programmierung ist vielen Entwicklern einfach nicht vertraut. Hinzu kommt, dass die Prinzipien der objektorientierten Programmierung zwar durchaus bekannt sind, aber die meis- ten Sprachen doch auf klassenbasierte Implementierungen setzen. Es ist also nicht verwunderlich, wenn viele Entwickler schon fast krampfhaft versuchen JavaScript die Idee der Klassen aufzudr¨ucken. Die irref¨uhrende Terminologie des sog. Kon- struktors (siehe Abschnitt 3.2.2) ist nicht minder unbeteiligt am Durcheinander [18, S. 90-94]. 3.1.3 JavaScript heute Heute stellt der Browser weiterhin die Hauptdom¨ane JavaScripts dar, dabei wird die Sprache durch viele Bibliotheken erg¨anzt, die dem Webdesigner bei seiner t¨aglichen Ar- beit behilflich sind, und die Di↵erenzen der verschiedenen Browser-Implementierungen nivellieren. Mit jQuery wird in Kaptitel 4 eine solche Bibliothek vorgestellt. Im Jahr 2009 hat JavaScript den Sprung aus dem Browser hinaus gescha↵t und kann seit dem universell d.h. auf Client- und Serverseite verwendet werden. Mit node.js schuf der Entwickler Ryan Dahl ein Framework, das sich durch hohe Performanz außerhalb des Browsers auszeichnet. Mit ECMAScript Version 6 befindet sich die n¨achste Novelle des Sprachstandards be- reits in der Entwicklung.7 3.2 Objekte in JavaScript JavaScript verf¨ugt neben den primitiven Datentypen Number, String und Boolean, den besonderen Typen undefined und null ¨uber Objekte. Zwei besondere Objekte, die durch die verschiedenen Laufzeitumgebungen bereitgestellt werden, sind Funkti- onsobjekte (Function) und Felder (Array) [15, S. 29]. Der Aufbau eines Objektes 7 Stand November 2014
  10. 10. Seminararbeit zum Kurs 1908 - Thema: JavaScript 8 orientiert sich dabei an dem bereits beschrieben Konzept der Slots, die in JavaScript Properties und im weiteren Verlauf der Arbeit einfach Eigenschaften oder Attribute genannt werden. Ein solches Attribut besteht dabei aus einem Schl¨ussel-Wert-Paar, wobei der Schl¨ussel stets vom Typ String sein muss, w¨ahrend der Wert einen beliebi- gen Datentypen annehmen kann [19, S. 48, 15, S. 115]. Da JavaScript frei von Klassen ist, m¨ussen Objekte auf andere Arten erstellt werden k¨onnen, dabei unterscheidet die Sprache insgesamt vier unterschiedliche Arten der Ob- jekterzeugung, die in den n¨achsten Unterkapiteln vorgestellt werden sollen. 3.2.1 Objektliterale Die einfachste Form der Erstellung von Objekten ist ex nihilo in Form sog. Objekt- literale, die eine Erzeugung an Ort und Stelle erm¨oglichen. Auf diese Art und Weise k¨onnen Zustand und Verhalten eines Objektes vollst¨andig definiert werden [20, S. 21]. Die dabei verwendete Notation nennt sich JavaScript Object Notation (JSON ), und wird im Bereich der Webtechnologie h¨aufig zur Serialisierung von Daten verwendet [21]. Listing 1: Objekterzeugung mittels Objektliteral 1 var clyde = { 2 name : "Clyde", 3 numberOfTusks : 2, 4 makeNoise : function () { 5 console.log("Tooeroooe!"); 6 } 7 } 8 9 console.log(clyde.name); // "Clyde" 10 console.log(clyde[" numberOfTusks "]); // 2 11 clyde.makeNoise (); // "Tooeroooe !" In Listing 1 wird ein Objekt namens ” Clyde“ erstellt, das neben den beiden Eigen- schaften name und numberOfTusks ¨uber die Funktion8 makeNoise verf¨ugt. Die Zeilen 9 und 10 des Beispiels zeigen die beiden Arten des Zugri↵s auf die Eigenschaften ei- nes Objektes. Dabei ist der Zugri↵ mittels sog. Dot-Notation (Zeile 9) ¨aquivalent zum Zugri↵ ¨uber den Schl¨ussel (Zeile 10), wobei sich Letzterer besonders gut f¨ur reflektive Aufrufe eignet. 3.2.2 Konstruktoren Neben den Objektliteralen ist eine Objekterzeugung mittels sog. Konstruktoraufruf m¨oglich. Konstruktoren sind gew¨ohnliche Funktionen, deren Name per Konvention groß geschrieben wird. Eine Funktion wird allerdings erst als Konstruktor verwendet, wenn sie mit dem Schl¨usselwort new aufgerufen wird. 8 Man k¨onnte genau so gut von einer Methode sprechen. Da in JavaScript jede Funktion zu einem Objekt geh¨ort (im Zweifelsfall zum sog. globalen Objekt) ist jede Funktion gleichzeitig auch ei- ne Methode. Um den funktionalen Charakter der Sprache zu unterstreichen, verwende ich den Ausdruck Funktion.
  11. 11. Seminararbeit zum Kurs 1908 - Thema: JavaScript 9 Listing 2: Objekterzeugung mittels Konstruktoraufruf 1 function Elephant(name) { 2 this.name = name; 3 this.numberOfTusks = 2; 4 this.makeNoise = function () { 5 console.log("Tooeroooe!"); 6 } 7 } 8 9 var clyde = new Elephant("Clyde"); 10 clyde instanceof Elephant; // true Analog zum vorherigem Beispiel wird in Listing 1 ein Objekt namens ” Clyde“ erzugt, allerdings erkennt man am Schl¨usselwort new in Zeile 9, dass ein Konstruktoraufruf zur Erzeugung verwendet wird. Ein solcher Aufruf hat eine Menge von Operationen zur Folge, die auf den ersten Blick nicht ersichtlich sind und daher an dieser Stelle noch einmal einzeln aufgeschl¨usselt werden sollen [18, S. 21, 22]: 1. Es wird ein neues (leeres) Objekt erstellt. 2. Die Prototypen-Eigenschaft des Objektes wird gesetzt. Was dies konkret bedeu- tet, und welcher Wert der Eigenschaft zugewiesen wird, wird detailliert in Kapitel 3.3 erl¨autert. 3. Die Variable this referenziert das neue Objekt und erm¨oglicht so eine Modifika- tion seiner Eigenschaften. 4. Sollte die Konstruktorfunktion keinen explizit R¨uckgabewert benennen, so wird das neue Objekt zur¨uckgegeben. Das Konzept der Konstruktoren wird h¨aufig kritisiert. Konstruktoren erwecken durch ihren Namen und ihre Syntax den Eindruck JavaScript verf¨uge ¨uber Klassen. Die Ver- wendung des Schl¨usselwortes new in Kombination mit Zuweisungen an die Variable this innerhalb der Konstruktorfunktionen erinnern stark an die Verwendung von Kon- struktoren in klassenbasierten Sprachen wie Java oder C#, und f¨uhren bei unerfahrenen Programmierern und JavaScript-Anf¨angern zu vermeidbaren Verst¨andnisproblemen. An dieser Stelle sei zudem noch einmal erw¨ahnt, dass Konstruktoren gew¨ohnliche Funk- tionen sind, die auch ohne das Schl¨usselwort new aufgerufen werden k¨onnen. Leider wird in diesem Fall die Selbstreferenz this an das globale Objekt gebunden, was unter Umst¨anden zu schwer nachvollziehbaren Fehlern f¨uhren kann (siehe Listing 3). Die Konsequenz ist, dass einige Autoren von der Verwendung von Konstruktoraufrufen abraten und stattdessen dazu appellieren, die ¨ubrigen Formen der Objekterzeugung zu nutzen, die charakteristisch f¨ur prototypenbasierte Sprachen sind [20, S. 30]. Listing 3: Fehlerhafte Objekterzeugung 1 function Elephant(name) { 2 this.name = name; 3 } 4 5 var clyde = Elephant("Clyde"); // new fehlt 6 console.log(clyde.name) // Fehler 7 console.log(window.name) // "Clyde"
  12. 12. Seminararbeit zum Kurs 1908 - Thema: JavaScript 10 3.2.3 Klonung und Erweiterung In Abschnitt 2.3.1 haben wir bereits die M¨oglichkeit der Objekterzeugung durch Klo- nung bzw. Erweiterung kennengelernt. ECMAScript verf¨ugt seit Version 5.1 ¨uber die Funktion Object.create, die beide Arten der Objekterzeugung erm¨oglicht. Da auch Object.create ausgiebig Gebrauch von Prototypen macht, wird an dieser Stelle auf die ausf¨uhrliche Erl¨auterung verzichtet und auf die sp¨atere Betrachtung in Kapitel 3.5.2 verwiesen. 3.3 Prototype-Eigenschaft Im vorherigen Kapitel wurde bereits mehrfach die sog. Prototyp-Eigenschaft eines Objektes angesprochen. Diese spezielle Eigenschaft referenziert ein weiteres Objekt, n¨amlich seinen sog. Prototypen. In JavaScript entsprechen Prototypen dem bereits vorgestellte Konzept des Parent-Slots, das bereits am Beispiel von Self erl¨autert wur- de. Die Bedeutung des Begri↵s ” Prototyp“ ist in JavaScript allerdings mehrfach belegt und soll an dieser Stelle genauer betrachtet werden [23, S. 83, 24]. • Prototyp als Referenz auf das Elternobjekt: Der Begri↵ Prototyp kann zum einen, wie bereits erl¨autert, eine Referenz auf das Elternobjekt bezeichnen. Es handelt sich dabei um eine spezielle Eigenschaft eines Objektes, die durch den ECMAScript Standard spezifiziert wird. Diese Eigenschaft wird anlehnend an die Notation des Standards auch h¨aufig als [[Prototype]] bezeichnet. In ECMAScript 5.1 und fr¨uher bezeichnete [[Prototype]] eine interne Eigen- schaft eines Objekts, f¨ur die keine Zugri↵smethoden existierten. Einige Brow- serhersteller setzen sich in der Vergangenheit ¨uber den Standard hinweg und erm¨oglichten den Zugri↵ auf das Elternobjekt ¨uber die propriet¨are Eigenschaft proto . Diese Idee wurde im vorl¨aufigen ECMAScript 6 Standard aufgegrif- fen und in Form der Eigenschaft Object.prototype. proto ¨ubernommen [25, Kap. B.2.2.1]. • Prototyp als Konstruktoreigenschaft: Funktionen verf¨ugen ¨uber eine zu- s¨atzliche Eigenschaft namens prototype, auf die explizit zugegri↵en werden kann. Diese Eigenschaft spielt eine wichtige Rolle bei der Objekterzeugung, falls die Funktion als Konstruktur verwendet wird. [[Prototype]] und prototype be- zeichnen im Fall von Funktionen also zwei verschiedene Eigenschaften. 3.3.1 Object.prototype Wird ein Objekt mittels Objektliteral oder new Object() erzeugt, so verweist [[Proto- type]] auf einen besonderen Prototypen, n¨amlich Object.prototype. Object.proto- type ist ein besonderes Objekt, das von der entsprechenden Laufzeitumgebung be- reitgestellt wird, und eine Menge von Standardfunktionen (z.B. toString() und is- PrototypeOf()) bereitstellt. Object.prototype ist insofern besonders, da es selbst ¨uber keinen eigenen Prototypen verf¨ugt [26]. Listing 4: Object.prototype als besonderer Prototyp 1 o = {} 2 Object.getPrototypeOf (o) === Object.prototype; // true
  13. 13. Seminararbeit zum Kurs 1908 - Thema: JavaScript 11 3 Object.getPrototypeOf ( Object.prototype ) === null; // true 3.3.2 [[Prototype]] und Konstruktoren In Abschnitt 3.2.2 wurde bereits gezeigt, dass die Objekterzeugung mittels Konstruk- toraufruf ebenfalls ¨Anderungen am Prototypen eines Objeks durchf¨uhrt. Dem neu- en Objekt, das durch den Aufruf erstellt wurde, wird als [[Prototype]] der Wert der Prototyp-Eigenschaft (.prototype) des Konstruktors zugewiesen. Anders ausge- dr¨uckt: Die interne Prototypeneigenschaft ([[Prototype]]) referenziert bei Objek- ten, die mittels Konstruktoraufruf erzeugt wurden, das selbe Objekt wie die explizite Prototypen-Eigenschaft .prototype der Konstruktor-Funktion. Listing 5 verdeutlicht diesen Sachverhalt an einem praktischen Beispiel. Listing 5: ¨Anderungen an Prototyp-Objekten 1 function Elephant(name) { 2 this.name = name; 3 } 4 5 console.log( Elephant.prototype ); // {} 6 7 Elephant.prototype.numberOfTusks = 2; 8 Elephant.prototype.makeNoise = function () { 9 console.log("Tooeroooe!"); 10 } 11 12 var clyde = new Elephant("Clyde"); 13 clyde.numberOfTusks === 2; // true 14 clyde.makeNoise (); // "Tooeroooe !" 15 Object.getPrototypeOf (clyde) === Elephant.prototype // true Es wurde bereits mehrfach erw¨ahnt, dass Konstruktoren in JavaScript einfache Funk- tionen sind. Da Funktionen selbst ” first-class citizens“, also Objekte sind, verf¨ugen sie selbst auch ¨uber Eigenschaften. Eine dieser Eigenschaften ist, die bereits erw¨ahnte Eigenschaft prototype, die in Zeile 5 zun¨achst auf eine leeres Objekt verweist und bei Bedarf auch ge¨andert werden kann. In den Zeilen 7-10 wird eben dieses Prototypen- Objekt modifiziert und erh¨alt neben einem Attribut eine neue Funktion. Wird darauf- hin ein neues Objekt mittels Konstruktoraufruf erzeugt, so sieht man (in den Zeilen 13 und 14), dass dieses Objekt ebenfalls ¨uber die Eigenschaften des Prototypen verf¨ugt. Abbildung 4 stellt zur Verdeutlichung das resultierende Objektgeflecht noch einmal grafisch dar.9 3.4 Delegation in JavaScript Es stellt sich nun die Frage, wie im vorherigen Abschnitt ein Objekt auf die Eigenschaf- ten seines Prototypen zugreifen konnte. Dieser Mechanismus wird in JavaScript mittels 9 In Wirklichkeit handelt es sich bei dieser Grafik, die so oder so in ¨ahnlich in vielen Lehrb¨uchern und auf vielen Webseiten gefunden werden kann um eine Vereinfachung des Sachverhalts. An dem simplen Aufruf Elephant() sind in Wirklichkeit mehr Objekte beteiligt, da die Funktion selbst auch ¨uber die Eigenschaft [[Prototype]] verf¨ugt. F¨ur Details siehe [27].
  14. 14. Seminararbeit zum Kurs 1908 - Thema: JavaScript 12 Abbildung 4: Prototypen in JavaScript, Quelle: Eigene Darstellung Delegation realisiert und h¨aufig auch als Prototype-Chaining bezeichnet. Wird eine Ei- genschaft eines beliebigen Objektes abgefragt, so pr¨uft das Objekt zun¨achst lokal, ob es ¨uber diese Eigenschaft verf¨ugt. Ist dies der Fall, so wird die entsprechende Operation durchgef¨uhrt. Schl¨agt der Versuch allerdings fehl, so wird der Zugri↵ an das Objekt weitergeleitet, das mittels [[Prototype]] referenziert wird. Dieser Mechanismus wird so lange fortgesetzt bis Object.prototype erreicht wird. Sollte auch dort die gesuch- te Eigenschaft nicht gefunden werden, so wird abgebrochen, da Object.prototype bekanntlich ¨uber keinen weiteren Prototypen verf¨ugt [19, S. 71]. Listing 6: Delegation in JavaScript 1 function Elephant(name) { 2 this.name = name; 3 } 4 5 Elephant.prototype.numberOfTusks = 2; 6 Elephant.prototype.makeNoise = function () { 7 console.log(this.name + " says: Tooeroooe!"); 8 } 9 10 var clyde = new Elephant("Clyde"); 11 var fred = new Elephant("Fred"); 12 13 Elephant.prototype.eat = function () { 14 console.log("nom nom nom"); 15 } 16 17 clyde.eat (); // "nom nom nom" 18 19 fred.numberOfTusks = 1; // poor fred ;( 20 clyde.numberOfTusks === 2; // true 21 fred.numberOfTusks === 1; // true 22 23 fred.makeNoise (); // "Fred says: Tooeroooe !"; Wir wollen anhand des Listings 6 das Prinzip der Delegation in JavaScript noch einmal nachvollziehen. Nach der Definition des Konstruktors und der Erweiterung des Proto-
  15. 15. Seminararbeit zum Kurs 1908 - Thema: JavaScript 13 typen werden zwei konkrete Elefanten erzeugt. In den Zeilen 13-15 wird der Prototyp der beiden Elefanten nachtr¨aglich, d.h. nachdem die beiden Objekte bereits erzeugt wurden, um die Funktion eat() erweitert. In Zei- le 17 wird nun die nachtr¨aglich hinzugef¨ugte Funktion auf einem der beiden Objekte erfolgreich aufgerufen. Dieser Sachverhalt verdeutlicht, dass es sich bei einem Proto- typen um ein gew¨ohnliches Objekt handelt, das beliebig modifiziert werden kann. Es zeichnet sich nur als Prototyp aus, weil es durch [[Prototype]] eines beliebigen ande- ren Objektes referenziert wird. Der Mechanismus der Delegation sorgt daf¨ur, dass die beiden Objekte clyde und fred indirekt ¨uber den Zustand und das Verhalten ihres Prototypen verf¨ugen. Wir wollen nun den umgekehrten Fall betrachten und eine Eigenschaft eines bereits erzeugten Elefanten modifizieren. In Zeile 19 ” verliert“ Fred einen Stoßzahn. In den bei- den folgenden Zeilen sieht man, dass die Zuweisung nur Auswirkungen auf das Objekt fred hat. Dies erkl¨art sich dadurch, dass die Zuweisung die Erzeugung einer neuen Eigenschaft im Objekt selbst zur Folge hat, und nicht an den Prototypen delegiert wird. Das Objekt fred verf¨ugt nun also ¨uber einen eigenen Wert f¨ur die Eigenschaft numberOfTusks, was zur Folge hat, dass der Mechanismus des Prototype-Chaining be- reits vorzeitig f¨undig wird, und die Anfrage nicht an [[Prototype]] delegiert werden muss. Man nennt dieses Verhalten Shadowing und es bietet den Vorteil, dass lokale ¨Anderungen an einem Kind eines Prototypen nicht ungewollt alle anderen Kinder des gleichen Prototypen modifizieren. Abbildung 5 stellt die beiden Objekte und die Beziehung zu ihren Prototypen noch einmal grafisch dar. Abbildung 5: Delegation in JavaScript, Quelle: Eigene Darstellung 3.5 Vererbung in JavaScript Bisher wurde nur die Beziehung zwischen einem Objekt und seinem Prototypen be- trachtet. Dieser einstufige Zusammenhang entspricht im Wesentlichen der Beziehung zwischen einem Objekt und seiner Klasse in der klassenbasierten Programmierung.
  16. 16. Seminararbeit zum Kurs 1908 - Thema: JavaScript 14 Es ist allerdings leicht zu erkennen, dass sich mit dem Ansatz der Delegation eine mehrstufige Anordnung von verschiedenen Objekt erzielen l¨asst, mit der die klassenba- sierte Vererbung (implementation inheritance) simuliert werden kann. In der Literatur werden dabei verschiedene Ans¨atze diskutiert, die an dieser Stelle vorgestellt werden sollen. 3.5.1 Pseudo-klassenbasierte Vererbung Anhand von Listing 7 wollen wird die sog. pseudo-klassenbasierte Vererbung betrach- ten. Listing 7: Pseudo-klassenbasierte Vererbung 1 function Mammal (name) { 2 this.name = name; 3 } 4 5 Mammal.prototype.eat = function () { 6 console.log("nom nom nom"); 7 } 8 9 function Elephant(name) { 10 this.name = name; 11 this.numberOfTusks = 2; 12 } 13 14 Elephant.prototype = new Mammal (); 15 Elephant.prototype.makeNoise = function () { 16 console.log(this.name + " says: Tooeroooe!"); 17 } 18 19 var clyde = new Elephant("Clyde"); 20 clyde.name === "Clyde"; // true 21 clyde.numberOfTusks === 2; // true 22 clyde.eat (); // "nom nom nom" 23 clyde.makeNoise (); // "Clyde says: Tooeroooe !"); Diese Form der Vererbung in JavaScript orientiert sich stark an der klassenbasierten Vererbung. Es werden zwei Konstruktoren definiert, deren Prototypen ¨uber zus¨atzliche Eigenschaften verf¨ugen. Die tats¨achliche Implementierung der Vererbung findet in Zei- le 14 des Listings 7 statt. Durch das ¨Uberschreiben der Prototyp-Eigenschaft des Konstruktors wird ein neues Objekt (ein S¨augetier) erzeugt, dessen interne [[Proto- type]]-Eigenschaft auf Mammal.prototype verweist. Das entstandene Objektgeflecht ist in Abbildung 6 dargestellt. Dieser h¨aufig verwendete Ansatz wird gerne um weiteren Funktionalit¨aten, wie z.B abstrakten Klassen, erweitert (siehe z.B. [15, Kap. 9.7.4]. Es gibt allerdings auch Kritik an dieser Art der Realisierung von Vererbung, die im Wesentlichen mit der Verwendung von Konstruktoraufrufen zusammenh¨angt. Neben der bereits bekannten Kritik an der Mechanik des Konstruktoraufrufs in JavaScript, ist diese Variante im Entwurf unvorteilhaft. Zum einen wird durch den Aufruf new Mammal() in Zeile 14 ein konkretes S¨augetier erzeugt, obwohl man ja eigentlich nur einen Prototypen ben¨otigt.10 Es findet also konzeptionell eine Vermischung zwischen 10 Elephant.prototype = Mammal.prototype; ist ¨ubrigens auch keine Option, da dadurch alle S¨augetiere zu Elefanten w¨urden und umgekehrt.
  17. 17. Seminararbeit zum Kurs 1908 - Thema: JavaScript 15 Abbildung 6: Pseudo-klassenbasierte Vererbung, Quelle: Eigene Darstellung den Objekten, die konkrete Instanzen repr¨asentieren, und Objekten, die Klassen re- pr¨asentieren, statt. Auf den ersten Blick k¨onnte man ebenfalls meinen, es f¨ande, bedingt durch den Aufruf in Zeile 14, eine Verkettung von Konstruktoraufrufen statt. Dies erweist sich allerdings als falsch, denn wird ein neues Objekt mit new Elephant() erstellt, so wird keineswegs der Konstruktor des S¨augetiers (Zeile 1) aufgerufen, stattdessen m¨ussen die geerbten Attribute in der Konstruktorfunktion der ” Subklasse“ wiederholt werden (Zeile 10).11 Der Konstruktor des S¨augetiers wird in Listing 7 lediglich einmal zur Erzeugung des Prototypenobjektes ausgef¨uhrt. Da zum Zeitpunkt des Aufrufs auch keine sinnvol- len Daten zur Verf¨ugung stehen, werden auch keine Argumente an den Konstruktor ¨ubergeben. Dies kann zus¨atzlich zu unvorhergesehenen Komplikationen f¨uhren, wenn der Konstruktor sinnvolle Werte f¨ur seine korrekte Ausf¨uhrung ben¨otigt [20, S. 48, 18, S. 102]. 3.5.2 Prototypenbasierte Vererbung Bis zur Freigabe des ECMAScript Standards in der Version 5.1 war die im vorheri- gen Abschnitt vorgestellte Methode die bevorzugte Art und Weise Vererbung in Java- Script zu simulieren. Mit der genannten Version des Standards wurde die Funktion Object.create() eingef¨uhrt, die einen nat¨urlicheren Weg zur Realisierung von Verer- bung erm¨oglicht. Die Funktion erm¨oglicht eine Vererbung unter Objekten, unabh¨angig von Klassenobjekten und Konstruktoren, durch Klonung und Erweiterung existierender Objekte. Sie wird wahlweise mit einem oder mit zwei Argumenten aufgerufen, wobei das erste Argument stets das bereits vorhandene Objekt erwartet, das der [[Proto- type]]-Eigenschaft eines neu erzeugten Objektes zugewiesen werden soll [18, S. 109 f.]. Die Funktionsweise soll an Listing 8 nachvollzogen werden. Listing 8: Object.create Polyfill 1 if (typeof Object.create !== 'function ') { 2 Object.create = function (o) { 11 In Abschnitt 3.5.3 wird gezeigt, wie man zumindest diese Unsch¨onheit beseitigen kann.
  18. 18. Seminararbeit zum Kurs 1908 - Thema: JavaScript 16 3 function F() {} 4 F.prototype = o; 5 return new F(); 6 }; 7 } 8 9 newObject = Object.create (oldObject); Listing 8 zeigt eine m¨ogliche Implementierung der Methode Object.create() und gleichzeitig einen sog. Polyfill, einen Quelltext, der dazu dient Browserinkompatibi- lit¨aten zu schließen, indem eine propriet¨are Funktionalit¨at mit bereits standardisierten Mitteln nachgestellt wird. In diesem konkreten Fall handelt es sich um eine Imple- mentierung, die eine eingeschr¨ankte Version von Object.create() bereitstellt [23, S. 91, 20, S. 22]. In Zeile 3 wird ein tempor¨arer Konstruktor erstellt, dessen prototype- Eigenschaft im n¨achsten Schritt mit dem ¨ubergebenen Objekte o ¨uberschrieben wird. Zeile 5 hat zur Folge, dass ein neues Objekt zur¨uckgegeben wird, dessen [[Proto- type]]-Eigenschaft auf das ¨ubergebene Objekt o verweist.12 Die standardisierte Implementierung der Funktion bietet zus¨atzlich die M¨oglichkeit ei- ne Menge von Eigenschaften, in Form eines weiteren Parameters, zu ¨ubergeben, um die das neue Objekt erweitert wird. Listing 9: Klonung und Erweiterung von Objekten 1 var clyde = { name : "Clyde", numberOfTusks : 2 } 2 3 // "cloning" 4 var fred = Object.create (clyde); 5 fred.name = "Fred"; 6 fred.numberOfTusks === 2; // true 7 fred.african = true; 8 9 // extending 10 var bonnie = Object.create (fred , { 11 isMatriarch: { 12 configurable: true , 13 enumerable: true , 14 value: true , 15 writable: true 16 }, 17 name: { 18 configurable: true , 19 enumerable: true , 20 value: "Bonny", 21 writable: true 22 } 23 }); 24 25 bonnie.name === "Bonny"; // true 26 bonnie.isMatriarch === true; // true Im Listing 9 wird Object.create() verwendet, um eine mehrstufige Beziehung zwi- schen Objekten zu realisieren. Die Zeile 4 zeigt die Verwendung der Funktion zur 12 Laufzeitumgebeungen, die ECMAScript 5.1 unterst¨utzen, bieten nat¨urlich native Implementierun- gen dieser Funktion an.
  19. 19. Seminararbeit zum Kurs 1908 - Thema: JavaScript 17 Klonung eines existierenden Objektes. In den Zeile 10-23 erfolgt eine Erweiterung, des zuvor erstellen Klons, um die Eigenschaft isMatriarch. Die Erl¨auterung der Notation zur Erweiterung eines Objektes (configurable, enumerable usw.) w¨urde an dieser Stelle den Rahmen der Arbeit sprengen. Es ist lediglich darauf hinzuweisen, dass die Eigenschaft value den tats¨achlichen Wert, den die neu hinzugef¨ugte Eigenschaft er- halten soll, enth¨alt. Zus¨atzlich wird der Wert des bereits vorhandenen Attributs name in den Zeilen 17-21 ¨uberschrieben. Diese Form der Vererbung wird auch h¨aufig di↵erentielle Vererbung genannt und er- laubt in JavaScript sogar das Entfernen vorhandener Attribute. Das resultierende Ob- jektgeflecht wird in Abbildung 7 gezeigt. Abbildung 7: Prototypenbasierte Vererbung, Quelle: Eigene Darstellung 3.5.3 Mischformen In der j¨ungeren Literatur zu JavaScript finden sich zunehmend Mischformen aus den beiden vorgestellten Vererbungsmechanismen. So k¨onnen beispielsweise die Nachtei- le der pseudo-klassenbasierten Vererbung durch den Quelltext aus Listing 10 abge- schw¨acht werden [28, 19, S. 69-72, 18, S. 100-103]. Listing 10: Prototypenbasierte Vererbung 1 function Mammal (name) { 2 this.name = name; 3 } 4 5 function Elephant(name) { 6 Mammal.call(this , name); 7 this.numberOfTusks = 2; 8 } 9 10 Elephant.prototype = Object.create( Mammal.prototype ); 11 Elephant.prototype.makeNoise = function () { 12 console.log(this.name + " says: Tooeroooe!"); 13 } 14
  20. 20. Seminararbeit zum Kurs 1908 - Thema: JavaScript 18 15 var clyde = new Elephant("Clyde"); 16 clyde.name === "Clyde"; // true 17 clyde.numberOfTusks === 2; // true 18 clyde.makeNoise (); // "Clyde says: Tooeroooe !"); Die beiden wesentlichen Unterschiede zur pseudo-klassenbasierten Version werden in Zeile 10 ersichtlich, da dort der Konstruktoraufruf von Mammal durch einen Aufruf von Object.create(Mammal.prototype) ersetzt wurde. Dies bringt den Vorteil, dass die bereits erw¨ahnte Vermischung zwischen Instanzobjekten und Klassenobjekten aufgel¨ost wird, so dass zwei sauber voneinander getrennte Hierarchien gepflegt werden k¨onnen. Zudem erfolgt kein unn¨otiger Aufruf des Konstruktors Mammal, der zu unvorherseh- baren Programmabst¨urzen oder Nebene↵ekte f¨uhren kann. An dieser Stelle sei noch auf die Zeile 6 hingewiesen, die auch so im Beispiel der pseudo-klassenbasierten Ver- sion h¨atte auftauchen k¨onnen. Es handelt sich dabei um einen indirekten Aufruf des Konstruktors Mammal, bei dem der Inhalt des ersten Arguments an die lokale Variable this innerhalb des Konstruktors gebunden wird. In diesem Fall heißt das ¨ubergebene Argument ebenfalls this, da es ja das Objekt repr¨asentiert, das durch den Aufruf new Elephant() erzeugt wurde, und entsprechend initialisiert werden soll. 3.5.4 Mixins als Alternative Der Vollst¨andigkeit halber soll hier noch eine Alternative zur Vererbung gezeigt werden, die ohne Prototypen arbeitet. Diese Alternative stellen die sog. Mixins dar, die kurz am Quelltextbeispiel 11 nachvollzogen werden sollen [19, S. 84 f.]. Listing 11: Beispiel f¨ur die Implementierung eines Mixins 1 function mixin(receiver , supplier) { 2 for (var property in supplier) { 3 if ( supplier.hasOwnProperty (property)) { 4 receiver[property] = supplier[property] 5 } 6 } 7 return receiver; 8 } Das Schl¨usselwort in in der zweiten Zeile von Listing 11 erm¨oglicht den iterativen Zugri↵ auf alle Eigenschaften eines Objektes. Mit hasOwnProperty() kann gepr¨uft werden, ob die Eigenschaft eines Objektes von diesem Objekt selbst stammt oder mit- tels Delegation von einem Prototypen abgeleitet wurde. Handelt es sich um eine eigene Eigenschaft, so wird diese an den Empf¨anger (receiver) weitergegeben. Nach Been- den der Schleife verf¨ugt der Empf¨anger ¨uber alle Eigenschaften des Vorlage-Objektes (supplier). Mit dieser Methode w¨are es m¨oglich mehrere Objekte miteinander zu ver- mischen und so eine Art von Mehrfachvererbung zu implementieren, wobei allerdings schnell klar werden sollte, dass man sp¨atestens bei Eigenschaften mit gleichem Namen vor einem Problem st¨unde. 4 JavaScript in der Praxis Nachdem im vorherigen Kapitel JavaScript und dessen Prototypen vorgestellt wurden, befasst sich dieser Teil der Arbeit mit der professionellen Nutzung von JavaScript in
  21. 21. Seminararbeit zum Kurs 1908 - Thema: JavaScript 19 der Praxis. Der Schwerpunkt liegt hierbei auf der Untersuchung der weit verbreiteten Bibliothek jQuery. Nach einer kurzen Vorstellung der Software und ihres Funktions- umfangs, erfolgt im letzten Teil des Kapitels eine genauere Betrachtung von relevanten Quelltextausschnitten. 4.1 Das jQuery-Projekt Wichtigstes Merkmal der Implementierung von JavaScript in Browsern ist die sog. Do- cument Object Model-API, die bereits 1998 durch das World Wide Web Consortium (W3C) standardisiert wurde und einen einheitlichen Zugri↵ auf die Elemente eines HTML-Dokumentes erm¨oglicht. Diese Schnittstelle benennt diverse Funktionen, mit denen die hierarchisch angeordneten Elemente einer XML-Struktur modifiziert und durchlaufen werden k¨onnen [29]. In der Vergangenheit implementierten Browserhersteller diese Schnittstelle in ihren Produkten und erweiterten sie h¨aufig um eigene Funktionen, die mit der Zeit h¨aufig selbst in den Standard gelangten. Leider wiesen viele Browser Eigenheiten bei der Im- plementierung auf, die von den Nutzern h¨aufig durch Zwischenl¨osungen (z.B. der bereits vorgestellte Polyfill) kompensiert werden mussten. Die Folge war, dass im Laufe der Zeit Bibliotheken entstanden, die diese einzelnen Browserinkompatibilit¨aten kapselten und h¨aufig ¨uber weitere, eigene Funktionen verf¨ugten. Eine dieser Erweiterungen, die von vielen Entwicklern begr¨ußt wurde, war es CSS- Selektoren zur Auswahl von Elementen des DOMs zu nutzen, und so die unflexiblen Funktionen des W3C-Standards zu verbessern. Cascading Stylesheets boten bereits in der Version 1 im Jahr 1996 eine vielseitige M¨oglichkeiten auf die einzelnen Elemen- te eine HTML/XML-Dokuments zuzugreifen. W¨ahrend der Standard des W3C nur einen Zugri↵ auf DOM-Elemente ¨uber ihren Typ oder das Attribut ID vorsieht, un- terst¨utzten CSS-Selektoren weitere Zugri↵sm¨oglichkeiten ¨uber Klassen, Pseudoklassen und Pseudoelemente [30]. Dar¨uber hinaus ist die die Verwendung der Selektoren vielen Entwicklern gut bekannt. Der Entwickler John Resig war ebenfalls von dieser Idee ¨uberzeugt, bem¨angelte al- lerdings ihre Ausf¨uhrung in Form der damals verwendeten Bibliotheken (z.B. beha- viour.js). Resig entwicklelte daraufhin seine eigene Bibliothek namens jQuery, die im August 2005 ver¨o↵entlich wurde und bis heute aktiv gepflegt und genutzt wird. Kern- bestandteil der Bibliothek war der von ihm entwickelte Code zur Nutzung von CSS- Selektoren in JavaScript, um einzelne Element oder Gruppen von Elementen selektieren zu k¨onnen [31].13 Wie e zient diese Mechanik im Vergleich zu herk¨ommlichen Java- Script ist, zeigt Listing 12. Listing 12: Vergleich JavaScript vs. jQuery 1 // jQuery 2 $.post('www.example.com /login ', { username: 'fred ' }, function ( data) { 3 // Verarbeitung 4 }) 5 6 // JavaScript 13 Dieser Kern heißt heute Sizzle.js und wird als selbstst¨andiges Projekt unter http://sizzlejs.com/ weitergepflegt.
  22. 22. Seminararbeit zum Kurs 1908 - Thema: JavaScript 20 7 var httpRequest = new XMLHttpRequest () 8 httpRequest.onreadystatechange = function (data) { 9 // Verarbeitung 10 } 11 httpRequest.setRequestHeader ('Content-Type ', 'application/ x-www-form-urlencoded ') 12 httpRequest.open ('POST ', 'www.example.com /login ') 13 httpRequest.send ('username= ' + encodeURIComponent ('fred ')) Listing 12 zeigt einen asynchronen Serveraufruf mittels der POST-Methode des HTTP- Protokolls. Die Zeilen 2-4 zeigen die Implementierung mittels jQuery, die ¨ubrigen Zeilen die klassische Variante mit JavaScript. Der reduzierte Aufwand f¨ur den Programmierer wird durch den Umfang der beiden Beispiele deutlich. JQuery hat sich im Laufe der Jahre zu einem De-facto-Standard entwickelt. Viele Quelltext-Ausschnitte in Fachb¨uchern und auf Internetportalen nutzen die jQuery- Notation ohne explizit darauf hinzuweisen. Deutlich wird die hohe Verbreitung, wenn man sich in Abbildung 8 die Nutzung und Marktanteile der Bibliothek im Vergleich zur Konkurrenz anschaut. Von den beobachteten Internetseiten, die http://www.w3techs. com in regelm¨aßigen Abst¨anden untersucht, nutzen 35,1% ¨uberhaupt keine Bibliothe- ken. 61,3% der beobachteten Seiten nutzen jQuery, was einem Marktanteil von 93,4% entspricht.14 Die Webseite http://www.builtwith.com benennt f¨ur den November 2014 49,4 Mio. Internetauftritte, die Verwendung von der Software machen. Abgeschlagen auf dem zweiten Platz befindet sich der Konkurrent MooTools mit 3,6 Mio. Installationen. Die- sen starken Erfolg verdankt jQuery nicht nur der Selektor-Mechanik, sondern auch einer Menge von weiteren Funktionen, um die das Projekt im Laufe der Jahre erwei- tert wurde [32, 33]. Die wichtigsten Funktionen lauten: • DOM-Manipulation: Der wichtigste Einsatzzweck ist die bereits beschriebe- ne Ver¨anderung des Document Object Model innerhalb eines Webbrowsers. Be- reits existierende DOM-Elemente k¨onnen mittels CSS-Selektoren ausgew¨ahlt und ver¨andert werden. Neue Elemente k¨onnen bequem erzeugt und in die existierende Hierarchie eingef¨ugt werden. • Ereignisbehandlung: Als clientseitige Technologie nutzt JavaScript ausgiebig Techniken der Ereignisbehandlung. Die jQuery-Bibliothek unterst¨utzt den Ent- wickler mit einer Vielzahl von browserunabh¨angigen Ereignisfunktionen, die auf DOM-Elemente angewendet werden k¨onnen. Dabei bietet jQuery sogar die M¨og- lichkeit auf Ereignisse zuk¨unftiger Elemente, also Teilen des Dokuments, die nach- tr¨aglich dynamisch hinzugef¨ugt wurden, zu reagieren. • Animationen und E↵ekte: Um Nutzer auf ¨Anderungen innerhalb des Doku- mentes aufmerksam zu machen und ggf. ¨uber Erfolg und Misserfolg einer Aktion zu informieren, wird eine Menge von Animationen und E↵ekten angeboten.15 • AJAX: AJAX steht f¨ur Asynchronous JavaScript and XML und beschreibt ei- ne Technik basierend auf dem XMLHttpRequest-Objekt, einer Funktionalit¨at 14 Es ist zu beachten, dass Webseiten auch h¨aufig mehrere Bibliotheken gleichzeitig nutzen. 15 Das Projekt jQueryUI auf http://jqueryui.com/ erweitert diese Funktionalit¨at noch einmal deutlich.
  23. 23. Seminararbeit zum Kurs 1908 - Thema: JavaScript 21 Abbildung 8: Verbreitung verschiedener JavaScript Bibliotheken [Stand 15.12.2014], Quelle: w3techs.com des Browsers, die asynchrone HTTP-Anfragen an einen Server erm¨oglicht. Mo- derne Webanwendungen, die in Aufbau und Funktion an klassische Desktop- Applikationen erinnern (sog. Single Page Applications), w¨aren ohne AJAX nicht m¨oglich. Detaillierte Informationen zum Thema AJAX k¨onnen [34, Kap. 18] ent- nommen werden. JQuery bietet mit seinem ajax-Objekt eine vielseitig nutzbare Schnittstelle zur Verwendung von AJAX innerhalb diverser Laufzeitumgebungen. Ein Beispiel f¨ur einen solchen AJAX-Aufruf wurde bereits mit der Methode post un Zeile 2 von Listing 12 gebracht. F¨ur den Entwickler ergeben sich aus der Nutzung von jQuery einige Vorteile [35, S. 105 ↵.]: • Weniger Quelltext: ” Write less, do more“ lautet das Motto von jQuery. Das gezeigte Quelltextbeispiel (Listing 12) sollte vermittelt haben, dass jQuery dies durchaus gelingt. • Erh¨ohte Lesbarkeit: Die Tatsache, dass durch geschickte Nutzung von Ereig- nismethoden s¨amtlicher Quelltext in JavaScript vom eigentlichen XML/HTML getrennt werden kann (sog. unobtrusive JavaScript), erh¨oht zusammen mit den kurzen Quelltexten die Lesbarkeit.
  24. 24. Seminararbeit zum Kurs 1908 - Thema: JavaScript 22 • Browserkompatibilit¨at: Die Gew¨ahrleistung der Browserkompatibilit¨at wur- de nun bereits mehrfach erw¨ahnt. JQuery unterst¨utzt sieben g¨angige Browser, darunter zwei mobile Anwendungen. • Einfach zu erlernen: Durch die einfache Syntax, die Verwendung von CSS- Selektoren und gut dokumentierten Funktionen, die mit wenig Aufwand viele ¨Anderungen gleichzeitig am DOM zulassen, ist jQuery leicht zu erlernen. • Große Community: Mit der bereits besprochenen hohen Verbreitung geht auch eine sehr große Entwicklergemeinschaft einher. • Kostenlos: Die Bibliothek ist kostenlos und kann auf der Projektwebseite her- untergeladen werden oder ¨uber ein sog. Content Delivery Network (CDN) in das eigene Projekt integriert werden. • Erweiterbarkeit: JQuery bietet Erweiterungsm¨oglichkeiten, mit denen das Pro- jekt um zus¨atzliche Funktionen erg¨anzt werden kann. Wie die Erweiterung der Bibliothek technisch realisiert wird, ist unter anderem Inhalt des n¨achsten Ab- schnitts. Demgegen¨uber steht eine geringe Anzahl von Nachteilen: • Dateigr¨oße: Die Bibliothek ist durch den hohen Funktionsumfang mit einer Dateigr¨oße von 86 KByte sehr groß. Dies kann vor allem im mobilen Bereich zu langen Ladezeiten f¨uhren. • Verdr¨angung von JavaScript: Die hohe Verbreitung jQueries hat zur Folge, dass viele Entwickler kaum Kontakt mit den standardisierten Browser-APIs ha- ben und f¨ur viele Einsatzf¨alle nur noch die Bibliotheksfunktionen nutzen. Prinzi- piell spricht nichts gegen ein solche Nutzung, solange der Entwickler ¨uber Kennt- nisse der dahinter liegenden Sprache verf¨ugt und nicht blind auf fremde Imple- mentierungen vertraut. 4.2 Untersuchung ausgew¨ahlter Quelltextpassagen Der Erfolg der jQuery-Bibliothek h¨angt unter anderem stark von seiner einfachen Ver- wendung und der bereits erw¨ahnten Erweiterbarkeit ab. Diese beiden Erfolgsfaktoren w¨aren ohne die e↵ektive Nutzung JavaScripts funktionaler und prototypenbasierter Spracheigenschaften sicherlich nicht m¨oglich gewesen. An ausgew¨ahlten Teilen des Pro- jektquelltextes 16 soll diese Aussage belegt werden. 4.2.1 Initialisierung des jQuery-Objekts Kern der Implementierung von jQuery ist das sog. jQuery-Objekt. Es handelt sich dabei um ein JavaScript-Objekt, das alle Bibliotheksmethoden vereint. Bereits das Initialisieren diese Objektes macht ausgiebig Gebrauch von JavaScripts funktionalen Eigenschaften. 16 Stand 19.11.2014, Version 2.1.1
  25. 25. Seminararbeit zum Kurs 1908 - Thema: JavaScript 23 Listing 13: Erstmalige Erzeugung des jQuery-Objektes 1 (function( global , factory ) { 2 // call factory 3 }( typeof window !== "undefined" ? window : this , function( window , noGlobal ) { 4 // define factory 5 } Es handelt sich bei dem Konstrukt in Listing 13 um eine sog. Immediately Invoked Function Expression(IIFE), also um die Definition einer anonymen Funktion, die direkt ausgef¨uhrt wird. Die Bibliothek stellt so sicher, dass sie an der Stelle, an der sie in ein Projekt eingebunden wird, auch ausgef¨uhrt wird. Die Parameter der Funktion sind zum einen das globale Objekt, das durch die Laufzeitumgebung bereitgestellt wird, und zum anderen eine anonyme Funktion, die f¨ur die eigentliche Initialisierung des Objektes zust¨andig ist und vom Funktionsparameter als factory bezeichnet wird. Die Erzeugung eines jQuery-Objektes ist sehr simpel und wird in Listing 14 gezeigt. Listing 14: Erzeugung eines jQuery-Objektes 1 $("a") In Listing 14 wird ein Objekt erzeugt, das alle Elemente des Typs a, also alle(!) An- kerpunkte innerhalb des Dokumentes referenziert. Es f¨allt auf, dass f¨ur die Objekter- zeugung weder das Schl¨usselwort new noch eine explizite Benennung eines Prototypen genutzt wird. Listing 15: Initialisierung des jQuery-Objektes 1 // Define a local copy of jQuery 2 jQuery = function( selector , context ) { 3 // The jQuery object is actually just the init constructor ' enhanced ' 4 // Need init if jQuery is called (just allow error to be thrown if not included) 5 return new jQuery.fn.init ( selector , context ); 6 }, 7 ... 8 init = jQuery.fn.init = function( selector , context ) { 9 // initialization 10 ... 11 }; 12 13 // Give the init function the jQuery prototype for later instantiation 14 init.prototype = jQuery.fn; Dies wird erreicht, indem die Funktion jQuery selbst den Konstruktoraufruf t¨atigt und eine Funktion namens init auf dem Objekt jQuery.fn aufruft (Listing 15, Zeile 5). Die Funktion init konfiguriert, abh¨angig von den ¨ubergebenen Parametern, das neu erzeugte Objekt und ist somit die wahre Konstruktorfunktion der Bibliothek. Dies er- kl¨art auch die Zuweisung in der letzten Zeile des Listings 15. Da es sich bei init um den eigentlichen Konstruktor handelt, muss dieser Funktion auch der Prototyp zugewiesen werden, mit dem die sp¨atere [[Prototype]]-Eigenschaft des neuen jQuery-Objektes belegt werden soll.
  26. 26. Seminararbeit zum Kurs 1908 - Thema: JavaScript 24 4.2.2 Verwendung von Prototypen Bei jQuery.fn handelt es sich lediglich um eine Referenz auf jQuery.prototype, um den Code ¨ubersichtlicher und kleiner zu halten. Dieser Prototyp beinhaltet alle wich- tigen Funktionen der Bibliothek, die in der API des Projektes aufgelistet werden. Der Großteil der mehr als 10.000 Zeilen Quelltext beschreibt diese Funktionen und bindet sie an das Prototypen-Objekt. Die Bindung der Funktionalit¨at an jQuery.fn bietet zwei große Vorteile: 1. Der Mechanismus der Objekterzeugung bleibt performant und ressourcenscho- nend. Wird ein neues Objekt erstellt, so muss lediglich die Referenz auf den existierenden Prototypen kopiert, und nicht jede der vielen Bibliotheksfunktio- nen neu erzeugt werden (siehe letzte Zeile in Listing 15). 2. Die Erweiterung der Bibliothek gestaltet sich besonders einfach, da neue Funktio- nen oder Eigenschaften nur an den Prototypen angef¨ugt werden m¨ussen, wodurch alle bereits existierenden und zuk¨unftigen Objekte um diese Merkmale erg¨anzt werden. Da sich die Implementierung der Funktionalit¨at eigentlich im Prototypen-Objekt be- findet, macht jQuery ausgiebig vom Prinzip der Delegation Gebrauch. Wir betrachten dazu in Listing 16 die Funktion before, die es erm¨oglicht ein DOM-Element vor einem anderen einzuf¨ugen. Listing 16: Beispiel f¨ur die Verwendung von Delegation in der jQuery Bibliothek 1 before: function () { 2 return this.domManip( arguments , function( elem ) { 3 if ( this.parentNode ) { 4 this.parentNode.insertBefore ( elem , this ); 5 } 6 }); 7 }, Innerhalb der Funktion des Prototypen sieht man die Verwendung von this.parentNode, wobei this in diesem Fall den Aufrufer, also ein konkretes jQuery-Objekt, und nicht jQuery.fn selbst meint. 4.2.3 Weitere Besonderheiten im Entwurf Bei n¨aherer Betrachtung des Quelltextes fallen weitere Entwurfsentscheidungen auf, die teilweise ausgiebig Gebrauch von JavaScripts Sprachfeatures machen, und durch geschickte Implementierungen die Nutzung der Bibliothek deutlich vereinfachen. • Globale Referenz: Das jQuery-Objekt wird nach Initialisierung als globale Re- ferenz gespeichert. Dies hat den Vorteil, dass st¨andig eine Referenz auf den Pro- totypen jQuery.fn existent und somit unerreichbar f¨ur die Garbage Collection bleibt. Zum anderen fiel die Wahl des globalen Variablennamens auf ein ein- faches Dollarzeichen ($)17 , das zu der mehrfach vorgestellten und pr¨agnanten Kurzschreibweise zur Erzeugung von jQuery-Objekten f¨uhrt. 17 Siehe [36] f¨ur g¨ultige Identifizierer in JavaScript.
  27. 27. Seminararbeit zum Kurs 1908 - Thema: JavaScript 25 • Callback-Funktionen: Ereignisse und ihre Behandlung spielen in JavaScript im Allgemeinen und in jQuery im Speziellen eine wichtige Rolle, da durch die Verwendung im Browser auf eine Vielzahl von Benutzer- und Netzwerkereignisse reagiert werden muss. Hierbei kommt h¨aufig die funktionale Programmierung zur Anwendung, da mit ihr Ereignisfunktionen als Parameter ¨ubergeben, und bei Auftritt des Ereignisses an Ort und Stelle ausgef¨uhrt werden k¨onnen. • Wrapped Sets: Eine Entwurfsentscheidung, die die Verwendung der Biblio- theksfunktionen stark vereinfacht, ist die der sog. Wrapped Sets. Ein jQuery- Objekt, das mit einem Selektor initialisiert wird, durchsucht das Dokument nach Elementen, die diesem Selektor entsprechen. Das Ergebnis des Suchvorgangs ist eine beliebig große Menge von jQuery-Objekten, auf die alle bekannten Biblio- theksfunktionen angewendet werden k¨onnen, wodurch eine explizite Iteration ¨uber die Ergebnismenge entf¨allt. • Verkettung von Funktionsaufrufen: Die Funktionen des jQuery-Objektes ge- ben h¨aufig das Objekt selbst zur¨uck, und erm¨oglichen so eine einfache Verkettung von Bibliotheksfunktionen. 4.2.4 Praxisbeispiel Die aufgez¨ahlten Besonderheiten sollen abschließend in Listing 17 an einem eigenen Quelltextbeispiel erl¨autert werden. Listing 17: Verwendung von jQuery zur DOM-Manipulation 1 <html> 2 <head> 3 <script src="https: // code.jquery.com / jquery-2.1.1.js " type=" text/javascript"></script> 4 <script type="text/javascript"> 5 $(function () { 6 $("li").click(function () { 7 $(this).css('color ', 'red').fadeOut('slow '); 8 }); 9 }); 10 </script> 11 </head> 12 <body> 13 <ul> 14 <li>Clyde </li> 15 <li>Fred </li> 16 <li>Bonny </li> 17 </ul> 18 </body> 19 </html> Listing 17 zeigt eine HTML-Seite mit einer ungeordneten Liste, die drei Eintr¨age enth¨alt. Der JavaScript-Quelltext startet in Zeile 5 mit dem sog. Document-Ready- Event, einer Callback-Funktion, die ausgel¨ost wird, sobald der Browser das DOM vollst¨andig geladen hat. In Zeile 6 wird zun¨achst nun ein neues jQuery-Objekt mit dem Selektor ” li“, also ein WrappedSet aus jQuery-Objekten, die ¨uber das HTML-Tag li verf¨ugen, erzeugt. Jedem
  28. 28. Seminararbeit zum Kurs 1908 - Thema: JavaScript 26 dieser Elemente wird nun ein neuer Event-Listener zugewiesen, wobei die Zuweisung implizit f¨ur alle Elemente erfolgt (Zeile 6). Wird ein Element vom Benutzer angeklickt, so wird die ¨ubergebene Callback-Funktion aufgerufen, die bewirkt, dass die Farbe des Elements auf rot ge¨andert, und das Element daraufhin langsam ausgeblendet wird (Zeile 7). Der Aufruf dieser beiden ¨Anderungen erfolgt verkettet in Zeile 7. Mit dem Aufruf $(this) zeigt Zeile 7 ebenfalls ein Beispiel f¨ur die Konvertierung (Wrap) eines Standard-DOM-Objektes zu einem jQuery-Objekt. An diesem kurzen Beispiel sieht man, wie e zient sich die Arbeitet mit der Bibliothek gestaltet. Mit lediglich vier verst¨andlichen Zeilen Quelltext wurden drei DOM-Elemente optisch ver¨andert, animiert und um eine Ereignisbehandlung erg¨anzt, nachdem gepr¨uft wurde, ob sie bereits vom Browser korrekt geladen wurden. 5 Zuk¨unftige Entwicklung und Fazit Douglas Crockford bezeichnet JavaScript als die missverstandenste Programmierspra- che der Welt, denn vielen Entwicklern sind die funktionalen und prototypenbasierten Spracheigenschaften unbekannt18 , was sicherlich an der eingeschr¨ankten Nutzung zur DOM-Manipulation im Browser und der klassenbasierten ” Herkunft“ der Programmie- rer liegt. Die Kapitel 3 und 4 dieser Arbeit sollten gezeigt haben, dass die Sprache mit ihren Prototypen, dem m¨achtigen Konzept der Delegation sowie Closures ¨uber eine Menge von flexiblen Werkzeugen verf¨ugt, mit der sich weitaus mehr als die Modifika- tion von Webseiten erzielen l¨asst. Mit der schlechten Namenswahl der Sprache, dem Konzept der Konstruktoren und der unklaren Verwendung des Klassenbegri↵s durch viele Autoren wurden im Verlauf der Arbeit einige Makel JavaScripts in Bezug auf Prototypen aufgezeigt. Ein Blick auf die neuesten Entwicklungen des Sprachstandards und aktuelle Pra- xisb¨ucher (z.B. [18, 19, 20]) zeigt, dass der Verwendung von prototypenbasierter Pro- grammierung in JavaScript in den letzten Jahren erh¨ohte Aufmerksamkeit geboten wurde. Standardisierte Funkionen wie Object.create oder Object.isPrototypeOf brachten ernsthafte Alternativen zu den klassischen Entwurfsmustern JavaScripts, die sich vorwiegend auf die Nachahmung der klassenbasierten Programmierung konzen- trierten. Die ECMAScript Version 6, die sich noch im Entwurfsstadium befindet19 , erweitert sowohl die konstruktor- als auch die prototypenbasierten Merkmale der Sprache um neue Funktionalit¨aten. Mit der Einf¨uhrung des Schl¨usselwortes class wird ein Wrap- per f¨ur die pseudoklassenbasierte Vererbung, wie sie in Kapitel 3.5.1 beschrieben wurde, eingef¨uhrt.20 Die direkte Belegung von [[Prototype]] innerhalb von Objektliteralen, sowie die M¨oglichkeit, das Prototypenobjekt dynamisch zu ¨andern, erh¨ohen nochmals die Flexibilit¨at der Sprache. In Kapitel 4 wurde anhand praktischer Beispiele gezeigt, wie jQuery JavaScripts Sprachei- genschaften einsetzt, um eine performante, robuste und leicht verwendbare Nutzung seiner Bibliotheksfunktionen zu erm¨oglichen. Die Vielseitigkeit der Sprache wird noch deutlicher, wenn man sich aus JavaScripts 18 Vor Anfertigung dieser Arbeit z¨ahlte sich der Autor ebenfalls dazu. 19 Stand: 02.12.2014 20 Die Benennung des Schl¨usselwortes selbst empfindet der Autor als sehr zweifelhaft.
  29. 29. Seminararbeit zum Kurs 1908 - Thema: JavaScript 27 Hauptdom¨ane, dem Browser, entfernt, denn durch die flexible Paarung aus funktio- naler und prototypenbasiert Entwicklung hat die Sprache ihren Weg in diverse ande- re Einsatzgebiete gefunden. Mit node.js21 existiert seit 2009 ein Framework, das die serverseitige Implementierung von Webseiten mit JavaScript erm¨oglicht. Node.js bie- tet dabei den Vorteil client- und serverseitig die selbe Sprache zu nutzen, wobei der Schwerpunkt auf der Verwendung des Ereignismodels (non-blocking I/O) JavaScripts liegt. Außerhalb des WWW dient die Sprache haupts¨achlich als Alternative zu existie- renden Scriptsprachen und DSLs, so verwenden Applikationen wie beispielsweise der Adobe Acrobat Reader, die dokumentenbasierte Datenbank MongoDB oder die Spiel- Engine Unity allesamt JavaScript als Scriptsprache, und tragen zur Verbreitung der prototypenbasierten Programmierung bei. 6 Anhang Abbildungsverzeichnis 1 Schematische Darstellung eines Objektes mit n+1 Slots, Quelle: Eigene Darstellung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 2 Schematische Darstellung der Delegation, Quelle: Eigene Darstellung . 5 3 Forwarding vs. Delegation, Quelle: http://bit.ly/1yGzr2y . . . . . . 5 4 Prototypen in JavaScript, Quelle: Eigene Darstellung . . . . . . . . . . 12 5 Delegation in JavaScript, Quelle: Eigene Darstellung . . . . . . . . . . . 13 6 Pseudo-klassenbasierte Vererbung, Quelle: Eigene Darstellung . . . . . 15 7 Prototypenbasierte Vererbung, Quelle: Eigene Darstellung . . . . . . . 17 8 Verbreitung verschiedener JavaScript Bibliotheken [Stand 15.12.2014], Quelle: w3techs.com . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 Literatur [1] Antero Taivalsaari. Classes vs. prototypes - Some Philosophical and Historical Observations⌧. In: Journal of Object-Oriented Programming (1996). [2] Stanford Encyclopedia of Philosophy. Plato. 2013. url: http://stanford.io/ 1pjfY82 (besucht am 18. 11. 2014). [3] Stanford Encyclopedia of Philosophy. Aristotle. 2011. url: http://stanford. io/11sN62m (besucht am 18. 11. 2014). [4] Ludwig Wittgenstein. Philosophische Untersuchungen. Frankfurt am Main: Suhr- kamp, 1971. isbn: 3-518-06514-9. [5] George Lako↵. Women, fire, and dangerous things : what categories reveal about the mind. Chicago: University of Chicago Press, 1987. isbn: 0-226-46804-6. [6] Alan Borning. Classes versus Prototypes in Object-Oriented Languages⌧. In: Proceedings of the ACM/IEEE Fall Joint Computer Conference. November 1986. 1986, S. 36–40. isbn: 0-8186-4743-4. 21 http://nodejs.org/
  30. 30. Seminararbeit zum Kurs 1908 - Thema: JavaScript 28 [7] G¨unther Blaschek. Object-Oriented Programming with Prototypes. 1994. isbn: 978-3-642-78079-0. [8] Henry Lieberman. Using Prototypical Objects to Implement Shared Behavior in Object-Oriented Systems⌧. In: OOPSLA86, ACM SIGPLAN. Bd. 21. 1. Nov. 1986. [9] Christophe Dony, Jacques Malenfant und Daniel Bardou. Classifying Prototype- based Programming Languages⌧. In: Prototype-Based Object-Oriented Program- ming: Concepts, Languages and Applications. Hrsg. von James Noble, Antero Taivalsaari und Ivan Moore. Springer, Feb. 1999. Kap. 2, S. 17–45. [10] Randall B. Smith und David Ungar. Programming as an Experience: The Inspi- ration for Self⌧. In: Proceedings ECOOP ’95. Bd. 952. LNCS”. Springer-Verlag, Aug. 1995, S. 303–330. [11] Marvin L. Minsky. A Framework for Representing Knowledge⌧. In: The Psy- chology of Computer Vision. New York: McGraw-Hill, 1975, S. 211–277. [12] F. Steimann. Moderne Programmiertechniken und -methoden: Kurseinheiten 1 - 7. FernUniversit¨at Hagen, 2012. [13] G¨unther Blaschek. The Omega Language - Introduction. url: http://bit.ly/ 1voFkB4 (besucht am 28. 11. 2014). [14] Charles Severance. JavaScript: Designing a Language in 10 Days⌧. In: IEEE Computer 45.2 (2012), S. 7–8. [15] David Flanagan und Dan Shafer. JavaScript: The Definitive Guide. O’Reilly & Associates, 1998, S. 776. isbn: 1-56592-392-8. [16] ECMA. Standard ECMA 262, ECMAScript Language Specification. url: http: //bit.ly/1vpiqe4 (besucht am 27. 11. 2014). [17] Douglas Crockford. JavaScript: The World’s Most Misunderstood Programming Language. 2001. url: http://bit.ly/1vpivyk (besucht am 27. 11. 2014). [18] Kyle Simpson. By Kyle Simpson You Don’t Know JS: this & Object Prototypes. O’Reilly Media, Aug. 2014. [19] Nicholas C. Zakas. The Principles of Object-Oriented JavaScript. 1. Aufl. No Starch Press, Feb. 2014. isbn: 978-1-593-27540-2. [20] Douglas Crockford. JavaScript: The Good Parts. 1st. O’Reilly Media, Mai 2008. isbn: 978-0-596-51774-8. [21] ECMA. ECMA-404: The JSON Data Interchange Format. 1st. ECMA (European Association for Standardizing Information und Communication Systems), Okt. 2013. url: http://bit.ly/1vRJ7u6 (besucht am 27. 11. 2014). [22] Mozilla Developer Network (MDN) - new operator. 2014. url: http://mzl.la/ 1xM2M9S (besucht am 27. 11. 2014). [23] David Herman. E↵ective JavaScript: 68 Specific Ways to Harness the Power of JavaScript. 1. Aufl. Addison-Wesley Professional, Dez. 2012. isbn: 978-0-321- 81218-6. [24] Mozilla Developer Network (MDN) - Object.prototype. proto . 2014. url: http: //mzl.la/1zSTq1S (besucht am 27. 11. 2014).
  31. 31. Seminararbeit zum Kurs 1908 - Thema: JavaScript 29 [25] Draft ECMA-262 6th Edition. 2014. url: http://mzl.la/1rTkdmK (besucht am 02. 12. 2014). [26] Mozilla Developer Network (MDN) - Object.prototype. 2014. url: http://mzl. la/1oAlm1C (besucht am 27. 11. 2014). [27] Joost Diepenmaat. Constructors Considered Mildly Confusing. 2013. url: http: //bit.ly/1lmComJ (besucht am 15. 11. 2014). [28] Mozilla Developer Network (MDN) - Introduction to Object-Oriented JavaScript. 2014. url: http://mzl.la/J1gPG5 (besucht am 15. 11. 2014). [29] W3C. Document Object Model. 2005. url: http://www.w3.org/DOM/ (besucht am 18. 11. 2014). [30] W3C. Cascading Style Sheets, level 1. 2008. url: http://www.w3.org/TR/REC- CSS1/ (besucht am 18. 11. 2014). [31] John Resig. Selectors in JavaScript. 2005. url: http://bit.ly/1voIe8X. [32] jQuery Foundation. jQuery API. 2014. url: http://api.jquery.com (besucht am 18. 11. 2014). [33] jQuery Foundation. History. 2014. url: https://jquery.org/history/ (be- sucht am 18. 11. 2014). [34] Stefan Koch. JavaScript - Einf¨uhrung, Programmierung und Referenz. 6. Aufl. K¨oln: Dpunkt-Verlag, 2011. isbn: 978-3-898-64731-1. [35] David Sawyer McFarland. JavaScript & jQuery: The Missing Manual. 3. Aufl. O’Reilly Media, Okt. 2014. isbn: 978-1-491-94707-4. [36] ECMA. ECMAScript 5.1, Identifier Names and Identifiers. 2014. url: http: //bit.ly/15MnkbU (besucht am 01. 12. 2014).

×