| 
Was sind Objekte?
Umsetzung der objektorientierten Programmierung
in JavaScript
Vererbung
Wer noch nie was über objektorientierte
Programmierung gelesen hat, kann sich das durchlesen, wer
weiss, was es ist, sollte gleich weiter zum Beispiel hopsen.
In gewisser Weise ist JavaScript eine 100 % objektorientierte
Sprache, allerdings mit der Besonderheit, dass man in der
Regel keine Objekte selbst generiert, sondern auf fertige
Objekte wie images, document, window, array etc. etc. zugreift.
Man kann aber, wenn das auch die wenigsten tun, mit JavaScript
selber Objekte kreieren. Wir verweisen hier bewusst nicht
auf die Perl und PHP Handbücher, wo unter objektorientierte
Programmierung mit Perl bzw. objektorientierte
Programmierung mit PHP einiges Grundsätzliches zur
objektorientierten Programmierung gesagt wird. Wir ziehen
es vor, nochmal Grundsätzliches dazu zu sagen. Im Prinzip
funktionniert der objektorientierte Ansatz in allen Programmiersprachen
ähnlich, die Idee dahinter ist immer die gleiche. Hinter
der objektorientierten Programmierung steht immer das Bemühen,
grosse Softwarepakete zu kapseln, das heisst dem Programmierer
kleine Softwarepakete zur Verfügung zu stellen, die bestimmte
Aufgaben lösen und die er nutzen kann, wenn ihm die Schnittstelle
zu diesen Paketen, und nur diese bekannt ist. Wer will kann
sich das auf einem hohen Abstraktionsniveau so klar machen.
In der objektorientierten Programmierung gibt es Substantive
und konkrete Dinger, auf die diese Substantive verweisen.
Das ist ja bekanntlich das Prinzip jeder natürlichen
Sprache. Man hat ein Substantiv, ein Dingwort, und das Dingwort
bezeichnet einen konkreten Gegenstand (Auto -> mein Auto,
Banane->Die Banane des Gorillas etc. etc.) Substantive
sind ein Konzept eines konkreten Dinges. Mit konkretem Ding
ist jetzt etwas gemeint, wo man sich z.B. den Schädel
daran anstossen kann, zum Beispiel ein Betonpfeiler. An dem
Konzept eines Betonpfeilers, dem Wort, kann man sich den Schädel
ja nicht anstossen. Was heisst hier Konzept eines konkreten
Dinges, bzw. Konzept einer Gruppe von konkreten Dingen ? Wenn
wir Auto sagen, haben wir ein Konzept im Kopf. Es ist ein
Ding, das mindestens drei Räder hat und sich aus eigener
Kraft von A nach B bewegen kann. Dieses Konzept ist aber noch
kein konkretes Ding. Meinen wir aber ein konkretes Auto, z.B.
mein Auto, dann haben wir es im Vokabular der objektorientierten
Programmierung mit einer Instanz zu tun. Volkswagen instanziiert
täglich ein paar tausend davon, das heisst, die bauen
Autos. Substantive sind in der objektorientierten Programmierung
Klassen, das heisst, abstrakte Baupläne für konkrete
Dinge. In diesen Bauplänen sind Methoden und Eigenschaften
definiert. Methoden sind bei der Klasse Auto z.B. fahren,
bremsen, hupen. Eigenschaften sind die Farbe des Autos, die
Marke, Alter etc. etc. Eine Methode ist jetzt das gleiche
wie eine Funktion und eine Eigenschaft ist das gleiche wie
eine Variable. Durch die Einführung der neuen Begriffe
Methode und Eigenschaften bringt man lediglich zum Ausdruck,
dass man es mit Funktionen und Variablen zu tun hat, die nur
im Zusammenhang mit einem Objekt auftreten können. Ein
Objekt kann nämlich nur die Eigenschaften und Methoden
haben, die im Bauplan festgelegt sind. Wir wären ja auch
alle echt verblüfft, wenn ein Auto Milch gibt, denn das
tut ja eigentlich eine Kuh. In der objektorientierten Programmierung
verhält es sich nun ähnlich wie in natürlichen
Sprachen, bzw. eine Kommunikation wäre nicht möglich,
wenn die Sprache nicht objektorientiert wäre, nicht aus
Klassen (Substantiven) bestünde, die auf konkrete Dinge
verweisen. Ein harmloser Satz wie "ich habe ihm eine
Uhr zum Geburtstag geschenkt" wäre sinnlos, wenn
wir nicht wüssten, welche Eigenschaften und Methoden
eine Uhr hat und welche Eigenschaften Geburtstag hat. Wir
müssen nur eine Schnittstelle finden zum Ohr desjenigen,
mit dem wir uns unterhalten, also den Schall, um uns verständlich
zu machen. Es interessiert uns nicht weiter, wie der dann
in seinem Gehirn eine Uhr vor seinem geistigen Auge entstehen
lässt. Wir erwarten dann eine Reaktion von unserem Gesprächspartner,
z.B. "wozu braucht der Penner eine Uhr, der kommt doch
eh immer zu spät". Wir interessieren uns nicht dafür
, wie er intern arbeitet und wie er die Information verwertet,
Hauptsache er produziert einen Output. Wir interessieren uns
auch in der objektorientierten Programmierung nicht dafür,
wie die Werte, die wir übergeben, intern verarbeitet
werden. Hauptsache wir sind in der Lage, etwas zu übergeben
und Hauptsache wir kriegen was zurück. Es ist wohl jedem
klar, dass der Ansatz, den natürliche Sprachen verfolgen,
der einzig machbare ist. Hätten wir das nicht, dann bräuchten
wir, um der Tatsache Ausdruck zu verleihen, dass Maria, David
und Ernst eine Uhr haben, jedesmal eine komplette Beschreibung.
Maria hat ein Ding, das macht tick-tack und hat zwei Zeiger
und........, David hat ein Ding, das macht tick-tack und...
, Ernst hat ein Ding, das macht tick-tack etc. etc. Also die
Angelegenheit wäre hoffnungslos. (Sie wäre übrigens
auch deswegen hoffnunglos, weil Zeiger selber eine Klasse
ist, den man dann auch erklären müsste). Wenn man
also gelegentlich die Behauptung findet, dass der Mensch eigentlich
objektorientiert denkt, dann ist das vielleicht sogar richtig,
was allerdings nichts an der Tatsache ändert, dass die
technische Umsetzung der objektorientierten Programmierung
wesentlich komplizierter ist, als die prozedurale Programmierung.
| Umsetzung
der objektorientierten Programmierung in JavaScript |
|
Die Umsetzung der objektorientierten Programmierung
in JavaScript weicht ab, von anderen Programmiersprachen wie
C++, C, Perl, PHP, Java. Alle diese Programmiersprachen bilden
Klassen, die alle Eigenschaften und Methoden einer Klasse
kapseln. Von dieser Klasse wiederum werden dann Instanzen,
also konkrete Objekte gebildet, die als Kinder der Klasse
all das können, was die Klasse kann. Die Idee ist in
JavaScript diesselbe, die konkrete technische Umsetzung allerdings
ist anders. Betrachten wir folgendes Beispiel. Wir betrachten
den Fall, dass das Objekt nur eine Methode hat, dann ist es
nämlich erstmal besonders einfach.
<html><head><title>Klassen
und Objekte</title>
<script language="JavaScript">
function initio(a,b,c)
{
this.zahl1=a;
this.zahl2=b;
this.text=c;
this.summe=this.zahl1+this.zahl2;
}
var objekt1=new initio(4,20,"Das Ergebnist ist");
alert(objekt1.text + " " + objekt1.summe);
var objekt2=new initio(5,30,"Die Addition dieser beiden
Zahlen ergibt");
alert(objekt2.text + " " + objekt2.summe);
</script>
</head>
<body>
mein erstes Objekt
</body>
</html>
Wer wissen will, was passiert, der muss hier
clicken. Was passiert ? Die Funktion initio() sieht erstmal
aus, wie eine ganz normale Funktion. Im Prinzip ist sie das
auch, es ist eine Funktion, die ein Objekt kreiert. Das Besondere
liegt weniger an der Funktion initio(), als an der Art und
Weise, wie sie aufgerufen wird.
var objekt1=new initio(4,20,"Das
Ergebnist ist");
Wir rufen hier nicht einfach eine Welt, Wald
und Wiesen Funktion auf, deren Rückgabewert wir an eine
Variable übergeben. Tatsächlich rufen wir eine Funktion
auf und sorgen dafür, dass die Parameter, die wir übergeben,
an ein Objekt gebunden werden. Wenn wir eine Funktion mit
new Name_der_Funktion() aufrufen, wird ein Zeiger auf das
Objekt mitübergeben und andereseits ist der Rückgabewert
dieser Funktion eben dieser Zeiger auf das Objekt. Der Zeiger
auf das Objekt, steckt in this.
Folglich sind haben this und
objekt1 bzw. this
und objekt2 denselben Wert.
Wenn wir also this.zahl1 schreiben,
dann ist es die erste Zahl unseres ersten Objektes, this
und objekt1 bezeichnen ja dasselbe
Objekt, mit objekt1.zahl1 auch wieder rausfischen können.
Nach diesem Schema können wir dann beliebig viele Objekte
generieren, von denen jedes individuelle Eigenschaften hat,
wie man ja deutlich sieht, da jedes alert Fenster die Objetkeigenschaften
des jeweiligen Objektes zeigt. Wie man an diesem einfachen
Beispiel auch sieht, ist es weniger Schreibarbeit, objektorientiert
zu programmieren. In diesem Falle rufen wir ja lediglich zweimal
(dreimal, viermal, fünfmal...) die Funktion initio()
auf und übergeben dann gleich die jeweiligen Werte, ohne
jedes mal den ganzen Code neu einzutippen. Der Einwand, der
jetzt vorgebracht werden kann ist klar. Man hätte das
gleiche auch mit einer normalen Funktion machen können,
die man eben zweimal aufruft. Wir werden sehen, dass sich
mit dem objektorientierten Ansatz Dinge realisieren lassen,
die nur mit einem größeren Aufwand möglich
sind, wenn man nur mit Funktionen arbeitet. Zuerst einmal
überlegen wir uns jetzt aber, sie wir unserem Objekt
nicht nur Eigenschaften, sondern auch Methoden zuweisen können.
Wass wir in unserem Beispiel spätestens dann wollen,
wenn wir nicht nur addieren sondern auch subtrahieren, multiplizieren,
dividieren wollen. Machen wir uns das anhand dieses Skriptes
klar.
<html><head><title>Klassen
und Objekte</title>
<script language="JavaScript">
function initio(a,b,c)
{
this.zahl1=a;
this.zahl2=b;
this.text=c;
this.multiplikation=function() { this.summe=this.zahl1*this.zahl2;}
this.division=function(){ this.summe=this.zahl1/this.zahl2;}
this.substraktion=function() {this.summe=this.zahl1-this.zahl2;}
}
var objekt1=new initio(4,20,"Das Ergebnis ist");
objekt1.multiplikation();
alert(objekt1.text + " " + objekt1.summe);
var objekt2=new initio(5,30,"Die Substraktion dieser
beiden Zahlen ergibt");
objekt2.substraktion();
alert(objekt2.text + " " + objekt2.summe);
</script>
</head>
<body>
mein erstes Objekt
</body>
</html>
Vielleicht ist es auch hier wieder günstig,
sich zuerst mal klar zu machen, was passiert, indem man
hier clickt. Innerhalb der Funktion initio() haben wir,
und das ist gewöhnungsbedürftig, drei weitere Funktionen definiert,
nämlich multiplikation(), division() und substraktion() von
denen wir dann anschliessend auch zwei Funktionen, nämlich
multiplikation() und substraktion() auch tatsächlich nutzen.
Nun lösen wir, nachdem wir das Objekt initialisiert haben,
die Funktion multiplikation() bzw. substraktion() aus.
objekt1.multiplikation();
objekt2.substraktion();
Da wir sie in der objektorientierten Schreibweise
auslösen, wird der Zeiger auf das Objekt ( objekt1 bzw.
objekt2) mit übergeben. Damit hat bei jedem Aufruf this
einen Wert, der auf das jeweilige Objekt zeigt, was wiederum
bewirkt, dass die Substraktion bzw. die Multiplilkation mit
den Werten durchgeführt wird, die zu diesem Objekt gehören.
Wir sehen also, dass JavaScript das Klassenkonzept ungewöhnlich
umsetzt. Alle Methoden des Objektes werden innerhalb der Funktion
deklariert, die auch das Objekt instanziiert. In anderen Programmiersprachen
werden alle Methoden zu einer Klasse zusammengefasst. Von
der Idee her, ist es aber dasselbe.
Unter Vererbung versteht man die Tatsache, dass
eine Unterklasse alle Eigenschaften einer Klasse erben kann,
so dass die Eigenschaften der Oberklasse nicht mehr neu definiert
werden müssen. Es wurde schon an vielen Stellen bemerkt,
dass erben der falsche Ausdruck ist, den vererben kann nur
jemand, der bereits tot ist, was bei einer Klasse nicht der
Fall ist, diese reicht ihre Eigenschaften und Methoden lediglich
an die Unterklasse weiter. Untechnisch betrachtet ist das
einfach einzusehen. Ein Sportauto ist eben ein Auto (ein Ding
auf drei oder vier Rädern, dass von A nach B fährt),
welches alle Eigenschaften von Auto hat und noch ein paar
spezifische des Sportautos. Der Ansatz, mit dem Vererbung
in JavaScript umgesetzt wird, weicht erheblich von der Art
ab, wie es in Perl, PHP, C#, Java, C++ etc. umgesetzt wird.
In JavaScript verwendet man zur Implementierung des Vererbungsmechanismus
prototype. Am besten wir machen uns das an einem Beispiel
klar. Nehmen wir an, wir wollen mit unseren zwei Zahlen nicht
nur eine der vier Grundrechenarten durchführen, sondern
auch die Umsatzsteuer berechnen (a ist also die Summe und
b der Umsatzsteuersatz). In diesem Fall müssten wir die
Funktion initio() erweitern, weil wir eine Funktion() zur
Durchführung der Umsatzsteuer im Moment nicht im Angebot
haben. Das Beispiel unten erweitert unser Programm um diese
Funktion.
<html><head><title>Klassen
und Objekte</title>
<script language="JavaScript">
function initio(a,b,c)
{
this.zahl1=a;
this.zahl2=b;
this.text=c;
this.summe=this.zahl1+this.zahl2;
}
initio.prototype.Umsatzsteuer=function()
{
this.steuer=this.zahl1*this.zahl2/100;
}
Finanzamt=new initio(100,15,"Die
Umsatzsteuer beträgt");
Finanzamt.Umsatzsteuer();
alert(Finanzamt.steuer);
</script>
</head>
<body>
mein erstes Objekt
</body>
</html>
Das funzt, wovon man sich überzeugen kann,
wenn man
hier clickt. Wir erhalten 15, was korrekt
ist, den 15 % von 100 sind 15. Entscheidend sind hierbei die
Zeilen
initio.prototype.Umsatzsteuer=function()
{
this.steuer=this.zahl1*this.zahl2/100;
}
mit denen wir unsere Funktion um die Funktion
Umsatzsteuer erweitern. Wenn wir jetzt, wie gehabt, mit
Finanzamt=new initio(100,15,"Die Umsatzsteuer
beträgt");
ein Objekt Finanzamt instantiieren, dann hat
dieses Objekt Finanzamt auch eine Methode Umsatzsteuer, die
wir in der Zeile
Finanzamt.Umsatzsteuer();
auch anprechen. Nachem diese Funktion aufgerufen
wurde, haben wir eine Objektvariable steuer, die wir uns mit
alert(Finanzamt.steuer);
anzeigen lassen.
|
 |