Funktionen als Konstruktoren von Objekten

Javascript Objekte initialisieren, mit einer Funktion erzeugen

Für die Initialisierung eines mit new erzeugten Objekts kann auch eine Funktion benutzt werden. Wenn eine Funktion mit dem new-Operator aufgerufen wird, spricht man von einem Konstruktor oder einer Konstruktor-Funktion.

Konstruktor-Funktionen zur Erzeugung und Initialisierung von Objekten

Anders als herkömmliche Programmiersprachen wie Java und C hatte Javascript anfangs von Haus aus keine Klassen, aber die Konstruktoren verleihen Javascript eine ähnliche Funktionalität.

Konstruktor-Funktionen sehen aus wie normale Funktionen, aber sie werden mit dem Schlüsselwort new benutzt. Sie kommen zum Einsatz, um mehrere gleichartige Objekte mit denselben Eigenschaften und Methoden zu erzeugen und sind sozusagen eine Fabrik für die Serienfabrikation von Objekten.

Die einfachste Schreibweise ist

function Painting() {
    // Definitionen und Anweisungen	
}

let myPainting = new Painting();

In dieser einfachsten aller Schreibweisen gib es erst mal keinen Unterschied zu einer normalen Funktion. Nur der Aufruf mit dem Schlüsselwort new und der große Anfangsbuchstabe weisen darauf hin, das hier ein Objekt vorliegt. Es ist gängige Praxis (Programmierkonvention), die Namen von Objekten mit einem Großbuchstaben zu beginnen.

Objekt-Fabriken

Eine Konstruktor-Funktion bündelt nicht nur Anweisungen, um den Code übersichtlicher zu gestalten, sondern initialisiert darüber hinaus das Objekt.

Schritt 1
function Painting (painter, title, year, url) {
    this.painter = painter;
    this.title = title;
    this.year = " (" + year + ") ";
    this.url = url;
    
    this.showimg = function () {
    	let img = document.createElement("img");
    	img.setAttribute("src", this.url);
    	img.setAttribute("alt", this.title);
    	…
    	document.querySelector(".gallery").appendChild (img);
    }
}
Schritt 2
let bild1 = new Painting ("Botticelli", "Geburt der Venus", 1485, "botticelli.jpg");
let bild2 = new Painting ("Raphael", "Schule von Athen", 1509, "raphael.jpg");
let bild3 = new Painting ("Bruegel", "Die Kreuztragung Christi", 1564, "bruegel.jpg");

bild1.showimg();
bild2.showimg();
bild3.showimg();
  • Das Schlüsselwort function erzeugt eine Funktion mit dem Name Painting
  • Der Funktion werden die Parameter zugewiesen: painter, title, year und url.
  • Den Parametern werden Eigenschaften mit demselben Namen durch das Schlüsselwort this zugewiesen.

Nur niemals vergessen, das new vor den Aufruf der Konstruktor-Funktion zu setzen! Dann würde eine Funktion ohne return-Wert aufgerufen und das this innerhalb des Konstruktors würde auf Window statt auf Painting beziehen. Das produziert dann wiederum einen unvorhersehbaren Fehler.

this in Objekten

Innerhalb der Konstruktor-Funktion werden die Elemente des Objekts mit dem Schlüsselwort-Präfix this angesprochen. this verweist auf die aktuelle Instanz und fügt dem Objekt Eigenschaften hinzu oder modifiziert sie.

Außerhalb der Funktion erfolgt der Zugriff wie zuvor mit dem Objektnamen als Präfix gefolgt von einem Punkt gefolgt von einem Element oder einer Methode:

Schritt 3   console.log ('Bild 1: ' + bild1.title);

Während die Variablen einer Standard-Funktion außerhalb der Funktion nicht sichtbar sind, gibt der Punkt-Operator außerhalb der Funktion Zugriff auf die Eigenschaften eines Objekts.

Eine Konstruktor-Funktion ist nicht auf das Zusammenfassen von Elementen eines Objekts beschränkt, sondern kann also auch Anweisungen enthalten, z.B. um eine komplexere Initialisierung durchzuführen.

function Mitarbeiter(persNr) {
   this.persNr = persNr;
   ...
   let mydate  = new Date();	
   this.alter  = mydate.getFullYear() - parseInt(this.persNr.substring(2,6));
}

let mitarb = new Mitarbeiter('0119601234');
alert(mitarb.alter);

Mit this deklarierte Elemente werden als öffentliche (public) Elemente bezeichnet.

private und public

Wird innerhalb des Funktions-Konstruktors eine Variable durch das Schlüsselwort var oder let deklariert, ist diese Variable wie gewohnt nur innerhalb der Funktion bekannt und wird auch als privates Element bezeichnet.

Private Mitglieder werden vom Constructor erzeugt. Normale Variablen und Parameter des Constructors sind private Mitglieder. Javascript erzeugt einen erlesenen Country-Club …

function Adress(firstName, lastName, city) {
   this.firstName = firstName;
   this.lastName  = lastName; 
   this.city      = city;
   let passwort   = "geheim";
   let self       = this; 
}

Der Konstruktor legt zwei private Instanzvariablen an: passwort und self. Sie gehören zum Objekt, aber außerhalb des Objekts kann nicht auf diese Instanzvariablen zugegriffen werden und auch die public-Methoden des Objekts haben keinen Zugriff. Nur die privaten Methoden – das sind die inneren Funktionen des Constructors – können auf private Instanzvariablen zugreifen.

Die private Variable self ist eine Programmierkonvention. Sie wird gebraucht, um das Objekt den privaten Methoden zur Verfügung zu stellen und ist ein Workaround für einen Fehler in der ECMAScript Language Specification, der this in inneren Funktionen falsch belegt.

Eigenschaften mit Closures verbergen

Innere Closure-Funktionen isolieren Eigenschaften von externen Änderungen. Von Douglas Crockford, dem großen Mann der Javascript-Szene, stammt eine häufig zu sehende Programmierpraxis für Konstruktor-Funktionen mit Closures.

var Person = (function() {
    function Person(name) {
        this.getName = function() {
            return name;
        };
    }

    return Person;
}());

var p = new Person('John');
console.log('Person name: ' + p.getName());
delete p.name;
console.log('Person name: ' + p.getName() + ' ist privat und geschützt.');

delete p.name; wird nicht ausgeführt, denn durch die Closure-Notation ist die Eigenschaft isoliert und vor Änderungen geschätzt. Allerdings wird jetzt mit jeder Instanz von Person ein neues Closure erzeugt.

Symbol ("name")

Dagegen wiederum steht mit ES6 ein weiterer Weg zum Speichern von Objekt-Eigenschaften zur Verfügung: Symbole. Symbole ähneln privaten Namen, sind allerdings nicht ganz so privat wie der Begriff Symbol suggeriert.

var Person = (function() {
    var nameSymbol = Symbol('name');
​
    function Person(name) {
        this[nameSymbol] = name;
    }
​
    Person.prototype.getName = function() {
        return this[nameSymbol];
    };
​
    return Person;
}());
{ } constructor function