Top

OOP

ES6 Klassen

In JavaScript gibt es Klassen erst seit ES6.
Funktionen stellen in JavaScript Objekte vom Typ Function dar und können als Konstruktor genutzt werden, um Objekte vom Typ Object zu erstellen.
Arrow Funktionen können nicht als Konstruktor genutzt werden!

function User() {}

let user = new User();

Um Eigenschaften zu definieren, ist es wichtig let oder const zu verwenden. Damit diese nur innerhalb der Funktion gültig sind und nicht global manipuliert werden können.

function User() {
    const name = 'Dennis';
}

let user = new User();

console.log(user.name); // undefined

Um diese Eigenschaften nutzen zu können kann man sich ein Objekt mit entsprechender Methode zurückgeben lassen.

function User() {
    const name = 'Dennis';
    return {
        getName: function() {
            return name;
        }
    };
}

let user = new User();
console.log(user.getName()); // Dennis

Hier kann man sehen was JavaScript erstellt hat.

let user = new User();

console.log(User);  // User()
console.log(typeof User); // function
console.log(User.constructor); // Function()

console.log(user); // Object { name="Dennis", getName=function(), setName=function()}
console.log(typeof user); // object
console.log(user.constructor); // Object()

Eigene Objekte mit Eigenschaften und Methoden könnten diese Form haben.

function User(params) {
    if (!params) { params = {}; }
    let name = params.name || null; 
    let email = params.email || null;
    return {
        getName: function() {
            return name;
        },
        setName: function(param) {
            name = param;
        },
        getEmail: function() {
            return email;
        },
        setEmail: function(param) {
            email = param;
        }
    }
}

let user = new User({name:'Dennis'});
console.log(user.getName()); // Dennis
console.log(user.getEmail()); // null
user.setEmail('d@dbproductions.de');
console.log(user.getEmail()); // d@dbproductions.de
console.log(user.name); // undefined

Man kann auch eine Form ohne return Anweisung nutzen.

function User(params) {
    if (!params) { params = {}; }
    let name = params.name || null; 
    let email = params.email || null;
    this.getName = function getName() {
        return name;
    }
    this.setName = function setName(param) {
        name = param;
    }
    this.getEmail = function getEmail() {
        return email;
    }
    this.setEmail = function setEmail(param) {
        email = param;
    }
}

let user = new User({name:'Dennis'});
console.log(user.getName()); // Dennis
console.log(user.getEmail()); // null
user.setEmail('d@dbproductions.de');
console.log(user.getEmail()); // d@dbproductions.de
console.log(user.name); // undefined

Innerhalb einer Funktion kann man sicherstellen, dass diese mit new aufgerufen wird.

function User(params) {
    if (false === (this instanceof User)) {
        return new User(params);
    }
    ...
}

let user = User({name:'Dennis'});
console.log(user.getName()); // Dennis
console.log(user.getEmail()); // null
user.setEmail('d@dbproductions.de');
console.log(user.getEmail()); // d@dbproductions.de
console.log(user.name); // undefined

Wenn man Funktionen als Methoden aufruft, zeigen sie auf das jeweilige Objekt.
Ruft man sie als Funktionen auf, werden die Eigenschaften mit this global definiert.

function getName() {
    return this.name;
}
function setName(name) {
    this.name = name;
}
let user1 = {name: "Dennis", getName: getName, setName: setName};
let user2 = {name: "User", getName: getName, setName: setName};

console.log(user1.getName()); // Dennis
console.log(user2.getName()); // User
user2.setName("Peter");
console.log(user2.getName()); // Peter
console.log(user2.name); // Peter

Klassen

Klassen gibt es seit ES6 womit man das Beispiel oben in dieser Form schreiben könnte.

class User {
    constructor(params) {
        if (!params) { params = {}; }
        this._name = params.name || null;
        this._email = params.email || null;
    }
    get name() {
        return this._name;
    }
    set name(newName) {
        this._name = newName;
    }
    get email() {
        return this._email;
    }
    set email(newEmail) {
        this._email = newEmail;
    }
}

let user = new User({name: 'Dennis'});
console.log(user.name); // Dennis
console.log(user.email); // null
user.email = 'd@dbproductions.de';
console.log(user.email); // d@dbproductions.de

Es können auch Kind Klassen erstellt werden.
Wenn die Kind Klasse einen eigenen Konstructor besitzt muss super aufgerufen werden da man sonst nicht auf this zugreifen kann.

class Customer extends User {
    constructor(params) {
        if (!params) { params = {}; }
        super(params);
        this._payment = params.payment || null;
    }
    get payment() {
        return this._payment;
    }
    set payment(newPayment) {
        this._payment = newPayment;
    }
}

Klassennamen sind optional, Klassen können wie Objekte und Funktionen herumgereicht werden.
Statische Methoden, wenn benötigt, werden auch unterstützt.

let logFactory = () => {
    return class {
        constructor(userCls) {
            this._user = userCls;
        }
        log(msg) {
            console.log(msg, this._user);
        }
        static log(msg) {
            console.log(msg);
        }
    };
};

let logger = logFactory();
logger.log('log');

let logInstance = new logger(user);
logInstance.log('user log');

Man kann ein JSON Objekt mit .assign() Klassen Eigenschaften zuweisen.

class User {
    constructor(data) {
        Object.assign(this, data);
    }
}

let User = new User({"name": "Dennis", "list": ["a","b","c"]});
console.log(user.name); // Dennis