Poznajemy kolejne ciekawe przypadki dotyczące OOP w języku JavaScript. Lekcja krótka, ale ciekawa – do dzieła!

Pierwsza ciekawa rzecz – klasy dziedziczące po funkcjach:

function Person(name, age){
        this.name = name;
        this.age = age;
  }

class Worker extends Person {
    constructor(name, age, dept){
        super(name, age);
        this.dept = dept;
    }
}

let w1 = new Worker("John", 30, "HR");
console.log(w1);
//{ name: "John", age: 30, dept: "HR" }

Jak widać JS jest bardzo kompatybilny wstecz, nawet na takie rzeczy pozwala. Ok, teraz klasy abstrakcyjne:

class AbstractPerson {

    constructor(name, age){
         if(new.target === AbstractPerson){
            throw new Error("Abstract class cant be instantiated");
         }
         this.name = name; 
         this.age = age;
    }
}


class Worker extends AbstractPerson{
    constructor(name, age, dept){
        super(name, age);
        this.dept = dept;
    }
}

let worker = new Worker("John", 30, "HR");
console.log(worker);
//Object { name: "John", age: 30, dept: "HR" }

let person = new AbstractPerson("John", 30);
//Uncaught Error: Abstract class cant be instantiated

Jak widać new.target nie tylko służy do sprawdzania, czy zostało użyte słówko new, ale także do sprawdzania jaki konstruktor został wywołany. Dzięki temu możemy osiągnąć efekt podobny do klas abstrakcyjnych.

Ok, a teraz dziedziczenie klasy przez już istniejący obiekt:

class Person {

    constructor(name, age){
        this.name = name;
        this.age = age;
    }

    sayHi(){
        return "My name is " + this.name + " and Im " + this.age + " years old.";
    }
}


const obj1 = {
    name: "John",
    age: 30
};

Object.setPrototypeOf(obj1, Person.prototype);

console.log(obj1.sayHi());
//My name is John and Im 30 years old.

Korzystanie z super w obiektach:

class Person {

    constructor(name, age){
        this.name = name;
        this.age = age;
    }

    sayHi(){
        return "My name is " + this.name + " and Im " + this.age + " years old.";
    }
}


const obj1 = {
    name: "John",
    age: 30,
    job: "HR",
    sayHi(){
        return `${super.sayHi()} My job is ${this.job}`;
    }
};

Object.setPrototypeOf(obj1, Person.prototype);

console.log(obj1.sayHi());
//My name is John and Im 30 years old. My job is HR

Warto pamiętać, że z super możemy korzystać tylko w metodach zapisywanych zapisem skróconym (bez słowa function jak również bez funkcji anonimowych/strzałkowych).

Inaczej będzie syntax error:

const obj1 = {
    name: "John",
    age: 30,
    job: "HR",
    sayHi: function(){
        return `${super.sayHi()} My job is ${this.job}`;
    }
};

Object.setPrototypeOf(obj1, Person.prototype);

console.log(obj1.sayHi());
//SyntaxError: use of super property accesses only valid within methods or eval code within methods

Swoją drogą to świetna okazja, aby pokazać jak działa cały ten „super” w zasadzie „pod spodem”. Oto „ręczne” zawołanie super:

const obj1 = {
    name: "John",
    age: 30,
    job: "HR",
    sayHi: function(){
        let sayHiSuperCall = Object.getPrototypeOf(this).sayHi.call(this);
        return `${sayHiSuperCall} My job is ${this.job}`;
    }
};

Object.setPrototypeOf(obj1, Person.prototype);

console.log(obj1.sayHi());
//My name is John and Im 30 years old. My job is HR

W ten sposób powinniśmy już coraz więcej rozumieć z tego, co się w JS dzieje. Jeżeli jest ciężko musimy po prostu próbować dalej, bawić się kodem, poszukiwać dobrych wzorców w internecie i z czasem będzie lepiej.