Notationen und Kürzel in JavaScript

August 8th, 2008

JavaScript ist seit dem “Erscheinen” von AJAX ist der Bekanntheitsgrad von JavaScript unaufhaltsam gestiegen, mittlerweile ist es von modernen Webseiten schon nicht mehr wegzudenken. Spätestens nach dem Erscheinen von diversen JavaScript-Frameworks erhielt auch die Verwendung von weniger bekannteren Syntaxmöglichkeiten in JavaScript einen Aufschwung. Trotzdem sind viele dieser Syntaxmöglichkeiten in JavaScript nicht sehr weit verbreitet.

Function Expressions

Function Expressions sind momentan schon sehr weit verbreitet und in jedem JS-Framework vertreten. Function Expressions werden wie Funktionen deklariert, dies führt oft zu Missverständnissen beim Debuggen und Einlesen. Der Vorteil von Function Expressions liegt klar auf der Hand: Es kann, wann immer Expressions gültig verwendet werden können, eine Function Expression verwendet werden. Dies kann z.B als Rückgabewert oder Definition erfolgen.

Folgender Code zeigt eine normale Funktion und Function Expression als Rückgabe. An diesem Beispiel erkennt man gut den Vorteil von Function Expressions, jedoch auch wie verwirrend die Notation teilweise ist.

 

// normale Funktion

function checkDocument() {

 if(document)

 	alert("Das Document-Objekt ist verfügbar!");

}

window.onload = checkDocument();// Function Expression

window.onload = function() {

 if(document)

         alert("Das Document-Objekt ist verfügbar!");

}

Object Literal

Sehr oft werden Object Literals in den aktuellen JavaScript-Frameworks eingesetzt und zwar als Klassennotation. Diese sind seit JSON “entdeckt” wurde gerne gesehen und vorallem auch einfach einzusetzen. Klassen die mittels Object Literals definiert wurden, würden in anderen Programmiersprachen wie z.B PHP wahrscheinlich Helper-Klassen oder sogenannte statische Klassen genannt werden, aus dem Grund, dass bei diesen Klassen das Schlüsselwort “new” für eine neue Objektinstanz nicht verwendbar ist.

Folgendes Beispiel zeigt eine Sammlung von Daten, im Grunde nur Strings, in einem Object Literal. Um genau zu werden ist es nichts anderes als ein JSON-String. Man beachte die 2 verschiedenen Zugriffsmöglichkeiten auf die Eigenschaften bzw. Felder.

 

var MyCar = {

 'type' : 'Audi A3',

 'color' : 'Metallic Blue',

 'PS' : '124'

}// Möglichkeit mittels "."-Operator auf das Feld "type" zuzugreifen

alert(MyCar.type);

// Möglichkeit mittels Zugriff wie auf ein Array (also mit eckigen Klammern)

alert(MyCar['color']);

Wie man sieht hat man mit Object Literals also ein weiteres Speichermedium, dass vorallem einfacher und stärker handzuhaben ist als Arrays.

Object Literals werden jedoch auch für die oben angesprochenen Klassennotationen verwendet, vorallem in der Kombination mit den Function Expressions werden sie zu einem mächtigen Werkzeug.

Folgende Klasse zeigt ein einfaches Beispiel dieser Notation.

 

var MyClass = {

   'color' : 'white',

   'alert' : function() {

 alert(MyClass.color);

    }

}

MyClass.alert();

Konditional Operator

Ein recht bekannter Operator, der in fast allen gängigen Programmiersprachen zum Einsatz kommt bzw. kommen kann, ist auch in JavaScript vertreten. Um unübersichtliche If-Else-Verzweigungen für eine einzelne Variablenzuweisung zu verhindern, wurde der Konditional Operator ins Leben geführt.

Folgendes Beispiel zeigt die Anwendung des Konditional Operators in der Gegenüberstellung zu einer If-Else-Verzweigung.

 

// If-Else

if(document.getElementById('content'))

  var test = true;

else

  var test = false;// Konditional Operator

var test = document.getElementById('content') ? 'true' : 'false';

// test ist true

Or-Operator

Der logische Or-Operator in JavaScript (||) hat die besondere Fähigkeit das er bei Vergleichen von 2 Werten keinen boolschen Wert (also True oder False) zurückgibt, sondern das Element welches den Wert “true” besitzt.

Somit ergibt sich bei Vergleichen die Möglichkeit, einen Standardwert zu definieren. Auch in diesem Beispiel wird wieder der “normale” Weg und der Weg über den Or-Operator gegenübergestellt.

 

// Herkömmlicher Weg

var test = document.getElementById('test');

if(!test)

  test = document.getElementById('not_test');// Weg über Or-Operator

var test = document.getElementById('test') || document.getElementById('not_test');

Objekt dynamisch erweitern

March 19th, 2008

Manchmal will man in seiner Klassenkonstruktion (beispielsweise ein Framework) gewisse Objekte erweitern, obwohl das zu erweiternde Objekt unbekannt ist. Ein gutes Beispiel kann man sich hier ansehen: Link zu Developers-Guide.

Wir haben eine abstrakte Klasse oder ein Interface “Component” welche Funktionen ausführt die wir standardmäßig benötigen. Was wir wollen ist, Component mit einer noch unbekannten Klasse zu erweitern.

Grundsätzlich ist die Lösung in JavaScript recht einfach gehalten. Folgenden Ansatz hatte ich:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
function MyComponentClass() {
                this.init = function() {
 
                      alert("Function init() was called...");
 
                }
 
               this.doBold = function() {
 
                     alert("Function doBold() was called...");
 
               }
}
 
function Component(id) {
 
		var protectedId = id;
	        alert("Construcor was called and protectedId was set to " + protectedId);
 
		this.loadData = function() {
 
                    alert("Function loadData() was called...");
 
                }
 
                this.createIcon = function() {
 
                    alert("Function createIcon() was called...");
 
                }
 
            }
 
var class= "MyComponentClass";
var att = "42";
 
eval(class + ".prototype = new Component('"+att+"');");
eval("var obj = new "+class+"();");
 
obj.init();
obj.loadData();
obj.createIcon();
obj.doBold();

Auch wenn eval() im Spiel ist, ist es zwangsbeding nicht unsicher, insofern man richtig vorgeht und aufpasst welche Klassen man instanzieren möchte.

Klassennotation mittels JSON

March 14th, 2008

In vielen der heutzutage erhältlichen JavaScript-Frameworks, sind Klassen natürlich unumgänglich und werden häufig genutzt. Tiefe Einblicke in den Kern dieser Frameworks zeigt, dass diese Klassen meistens mittels JSON-Notation definiert werden.

Im Grunde sind Klassen die mittels JSON notiert wurden nichts anderes wie statische Klassen (auch gerne Helper-Klassen genannt) in vielen anderen Programmiersprachen. Das heißt diese Klassen sind nicht instanzierbar. Die Klasseninternen Methoden werden direkt angesprochen. Außerdem fallen Datenkapselung und Möglichkeiten wie das Prototyping bzw. Vererbung, ohne zusätzliche Funktionen programmieren zu müssen, weg.

Frameworks behelfen sich hier eigenen Techniken die aus dem JSON-Objekt eine instanzierbare Klasse und Datenkapselung, Prototyping, abstrakte Klassen und Interface-Klassen ermöglichen. Wie dies funktioniert werde ich ein anderes Mal erklären.

Wie kann so eine JSON-Klasse aussehen?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
var myJSONObj = { myself: "Im a static JSON Object",
 
callMyself : function() {
 
alert(this.myself);
 
},
 
alert : function(text) {
 
alert(text);
 
}
 
}
 
var myClassObj = function() {
 
this.myself = "Im a Class Object";
 
this.callMyself = function() {
 
alert(this.myself);
 
}
 
 this.alert = function(test) {
 
        alert(test);
 
 }
 
}
 
myJSONObj.callMyself();
 
myJSONObj.alert("Test");
 
var myClassObj = new myClassObj();
 
myClassObj.callMyself();
 
myClassObj.alert("Hihi");

Hier werden beide Klassenkonstrukte (einmal JSON-, einmal die Standard-Notation) aufgeführt. Beide besitzen die selbe Funktionalität. Eine öffentliche Eigenschaft “myself“, eine (privilegierte) öffentliche Methode “callMyself()” und eine (privilegierte) öffentliche Methode “alert()“.

Wie man jetzt schon gut sehen kann, ist es ohne zusätzliche Programmierung bei der JSON-Notation nicht möglich nicht-privilegierte öffentliche Methoden und private Methoden zu definieren. Außerdem ist das Prototype, sprich die Vererbung ohne mittelbar zuprogrammierte “Hacks” nicht möglich.

Wieso programmiert man dann überhaupt mit JSON-Notation, wenn Design Pattern, Vererbung usw. nur durch Zuprogrammierung möglich sind

Ganz einfach, man möchte sogenannte Helper-Klassen benutzen oder braucht nur eine “einfache” Klasse ohne Großes Getümmel. Im Grunde sind Helper-Klassen nichts anderes wie eine Ansammlung von Funktionen (bzw. Methoden) die klar strukturiert und geordnet nach Funktionsumfang sind.

Objektorientierte Programmierung in JavaScript

March 11th, 2008

In diesem Tutorial möchte ich die Möglichkeiten die JavaScript bezüglich der objektorientierten Programmierung zu bieten hat, aufzeigen.

Inhalt:

  • Vorwort
  • Klassen und Konstruktor definieren
  • Datenkapselung von Methoden und Eigenschaften
  • Vererbung
  • Nachwort

Vorwort

Viele halten JavaScript noch immer für den Grundsatz alles Bösen das in den letzten Jahren an Geblinke, Geblitze und anderen Greultaten die im Internet kursierten. Seit dem Web 2.0 konnte JavaScript einiges an Punkten gut machen und findet sich mittlerweile sogar in den Top 10 der beliebtesten Programmiersprachen. Die Anwendungsgebiete fallen hauptsächlich in die DOM-Manipulation, Effekte im Browser oder ähnliches. Ebenso hat JavaScript den schlechten Ruf unsicher zu sein, welcher jedoch durch das sandboxing um einiges verringert wird (ActiveX-Elemente ausgenommen) und durch gute Programmierung vernichtet wird.

JavaScript ist eine auf Objekten basierende Programmiersprache. Es gibt zahlreiche vordefinierte Objekte wie z.B das String oder Window-Objekt.

Die Objekt-orientierte Programmierung in JavaScript wird auch gerne mit JSON-Notation und Function-Expressions verwirklicht, jedoch kann man diese Klassen nicht direkt instanzieren, dass heißt es ist nicht wirklich möglich ein Objekt davon zu erzeugen. Auch verwenden manche JavaScript-Frameworks (Mootools, Prototype,jQuery,…) gerne eine eigene Funktion für das erstellen von instanzierbaren Klassen mit der Möglichkeit die JSON-Notation trotzdem nutzen zu können. Über dieses Verhalten werde ich das nächste mal sprechen.

Klassen und Konstruktor definieren

In JavaScript gibt es keine Klassen-Definition im herkömmlichen Sinne. Eine Klasse wird, wie in allen gängigen Programmiersprachen, mit dem Schlüsselwort “new” initialisiert.

Als Test-Klasse werden wir ein Auto verwenden und daran rumspielen.

function Car(CarColor) {
this.CarColor = CarColor;
}

Das ist also unsere Klassen-Definition. Wie man sehen kann gibt es in JavaScript kein explizites Schlüsselwort für eine Klasse. JavaScript unterscheidet nur anhand der Initialisierung der Funktion ob es eine Klasse ist oder nicht.

function Car(CarColor) {
this.CarColor = CarColor;
}
var Jeep = new Car('blue'); // Initialisierung des Objekts "Car"
alert(Jeep.CarColor); // Direkter Zugriff auf die Eigenschaft "CarColor"

Hier erstellen wir mittels “new” ein neues Objekt und übergeben dem Konstruktor den Parameter “CarColor”. Ganz recht, die Funktion ist eigentlich unser Konstruktor. Anschließend wird die öffentliche Eigenschaft “CarColor” mit dem übergebenen Parameter definiert und mittels alert wird die Eigenschaft “CarColor” am Bildschirm ausgegeben.

Datenkapselung von Methoden und Eigenschaften

Die Datenkapselung ist in der objektorientierten Programmierung natürlich ein wichtiges und unabdingbares Feature das natürlich auch in JavaScript nicht fehlen darf. In JavaScript existieren nur öffentliche (public) und private (private) Eigenschaften und sogenannte “privilegierte öffentliche Methoden”, “nicht-privilegierte öffentliche Methoden” und natürlich private Methoden.

function Car(CarColor) {
 
// öffentliche (public) Eigenschaft
this.CarColor = CarColor;
 
// privilegierte öffentliche Methode
this.setCarColor = function(newCarColor) {
this.CarColor = newCarColor;
}
}
 
var Jeep = new Car('blue');
alert(Jeep.CarColor);
Jeep.setCarColor('orange');
alert(Jeep.CarColor);

Hier definieren wir die “privilegierte öffentliche Methode” “setCarColor” mit einem Parameter. Beim Aufruf wird die “öffentliche Eigenschaft” “CarColor” überschrieben und anschließend wieder ausgegeben.

function Car() {
 
// private Eigenschaft
var CarTank = '100 Liter';
 
// privilegierte öffentliche Methode
this.setCarTank = function(newCarTank) {
 
CarTank = newCarTank; // Zuweisung des neuen Tankinhaltes
getCarTank(); // Aufruf der privaten Methode
 
}
 
var getCarTank = function() {
 
// Ausgabe der privaten Eigenschaft
alert(CarTank);
 
}
 
}
 
var Cabrio = new Car();
Cabrio.setCarTank('200 Liter');
alert(Cabrio.CarTank); // Liefert "undefined"
Cabrio.getCarTank(); // Liefert "is not a function"

Dieses Beispiel veranschaulicht die Zugriffsrechte der einzelnen Methoden und Eigenschaften. Die Eigenschaft “CarTank” ist privat und kann von außen nicht aufgerufen oder befüllt werden nur innerhalb der Klasse ist das hantieren mit der Eigenschaft möglich. Selbiges für die Methode “getCarTank”.

In JavaScript ist es möglich bestehende Methoden bzw. Objekte nachträglich zu beeinflußen. Dies funktioniert mittels sogenannten “Prototypen” auf die JavaScript basiert. Dies hat den Vorteil von mehr Unabhängigkeit und Flexibilität für den Programmierer.

function Car() {
 
// öffentliche Eigenschaft
this.CarName = "Audi";
// private Eigenschaft
var CarColor = "Black";
 
// private Methode
var setCarColor = function(newCarColor) {
 
CarColor = newCarColor;
 
}
 
// privilegierte öffentliche Methode
this.getCarInfosInside = function() {
 
setCarColor('Green');
alert("CarName:" + this.CarName + " CarColor:" + CarColor);
 
}
 
}
 
// nicht-privilegierte öffentliche Methode
Car.prototype.getCarInfosOutside = function() {
 
setCarColor('Green');
alert("CarName:" + this.CarName + " CarColor:" + CarColor);
 
}
 
var Audi = new Car();
Audi.getCarInfosInside(); // Liefert "Audi" und "Green"
Audi.getCarInfosOutside(); // Liefert "setCarColor" is not defined, "Audi" und "undefined"

Wie man hier gut sehen kann wird einmal die “privilegierte öffentliche Methode” “getCarInfosInside” aufgerufen (bitte entschuldigt meine Kreativen Methoden-Namen ) und einmal die “nicht-privilegierte öffentliche Methode” “getCarInfosOutside”. Die Methode in der Klasse hat natürlich vollen Zugriff auf alles was drinnen so abläuft, d.h ich kann auf alle Eigenschaftn und Methoden zugreifen. Die Methode außerhalb der Klasse kann lediglich auf öffentliche Eigenschaften und Methoden zugreifen.

Vererbung

Durch die Prototypen-Funktionen ist es möglich Vererbung in JavaScript zu benutzen.

// Superklasse
function Car(CarName) {
 
this.CarName = CarName;
this.CarWheels = "4";
 
}
 
// Subklasse
function Audi(CarName) {
 
// Dieser Konstruktor ruft den Konstruktor der Superklasse auf
this.constructor(CarName);
this.CarColor = 'Black';
 
this.getCarInfos = function() {
 
alert(this.CarName + " is " + this.CarColor + " and has " + this.CarWheels + " Wheels!");
 
}
 
}
 
Audi.prototype = new Car(); // Hier passiert die Vererbung
 
AudiA3 = new Audi('Audi A3');
Audi80 = new Audi('Audi 80');
 
AudiA3.getCarInfos(); // Liefert "Audi A3 is Black and has 4 Wheels"
 
Audi.prototype.setCarColor = function(newCarColor) {
 
this.CarColor = newCarColor;
this.getCarInfos();
 
}
 
Audi80.setCarColor('Yellow'); // Liefert "Audi 80 is Yellow and has 4 Wheels"

In diesem Beispiel haben wir eine Superklasse “Car” und die Subklasse “Audi”. “Car” besitzt 2 öffentliche Eigenschaften. Eine wird per Parameter befüllt, die andere ist es bereits. “Audi” besitzt eine 2 privilegierte öffentliche Methoden, dass sind “this.constructor” und “this.getCarInfos”. Wobei der Konstruktor nur dafür da ist um die Superklasse aufzurufen ohne sie extra nochmal initialisieren zu müssen. Anschließend passiert die Vererbung mittels dem Prototypen. Dann definieren wir 2 verschiedene Audi’s und lassen uns per “getCarInfos” die Audi A3-Daten ausgeben. Da wir alle Eigenschaften von der Superklasse geerbt haben können wir auf den Namen und die Anzahl der Reifen zusätzlich zugreifen.

Nachwort

Ich werde (hoffentlich) weitere Tutorials in Richtung JavaScript und dessen OO-Strukturen, veröffentlichen. Es gibt zahlreiche Syntax-”Geheimnisse” und Design Patterns, die zwar in anderen Programmiersprachen gerne und oft benutzt werden, jedoch in JavaScript so gut wie nicht bekannt sind keinen Anklang finden.

Konstruktive Kritik wandert bitte in die Kommentare.

Patrick