Class

Poza poznanymi w poprzednim rozdziale konstruktorami, do tworzenia własnych typów obiektów możemy też wykorzystać składnię class czyli klasy.

W niektórych miejscach internetu możesz natrafić na stwierdzenie, że klasy w Javascript są tak zwanym "syntactic sugar", co oznacza, że jest to w zasadzie tylko swego rodzaju nakładka na poznane w poprzednim rozdziale mechanizmy. Jest to poniekąd prawdą, ponieważ zasada działania poznana w poprzednim rozdziale w większości się nie zmienia, natomiast z pewnością upraszcza nam się kod.

Deklaracja klasy

Klasy są "specjalnymi funkcjami", które służą do tego samego co konstruktory. Ogólna deklaracja i użycie klasy ma postać:


class Animal {
    constructor() {
        ...
    }

    method1() {
        ...
    }

    method2() {
        ...
    }
}

//obiekty tworzymy tak samo jak w przypadku konstruktorów
const pet1 = new Animal();
const pet2 = new Animal();

Podobnie do klasycznych funkcji definicję klasy możemy też stworzyć jako wyrażenie const Animal = class {}, chociaż zapis taki jest raczej rzadko spotykany.

Gdy zbadasz sobie w konsoli powyższą klasę za pomocą console.dir(Animal), zobaczysz, że praktycznie jest ona tym samym co konstruktor z poprzedniego rozdziału. Tam była funkcja, i tu też jest funkcja. Tam konstruktor dostawał właściwość prototype, na którą wskazywały [[Prototype]] w pojedyńczych instancjach, to samo dzieje się i tutaj:

class

function AnimalFn() {
    ...
}

class Animal {
    ...
}

console.log(typeof Animal, typeof AnimalFn); //function, function
Object.getPrototypeOf(Animal) === Object.getPrototypeOf(AnimalFn) //true

class Animal {
    ...
}

const animal = new Animal();
Object.getPrototypeOf(animal) === Animal.prototype //true

constructor()

Każda klasa posiada specjalną funkcję constructor(), która jest automatycznie odpalana przy tworzeniu nowej instancji za pomocą słowa new.


class Animal {
    constructor(name, age) {
        this.name = name;
        this.age = age;
        console.log(`Zwierzak ${this.name} ma ${this.age} lata`);
    }

    method1() {
        ...
    }

    method2() {
        ...
    }
}

const animal = new Animal("pies", 3); //Zwierzak pies ma 3 lata

Funkcja constructor() jest w zasadzie tym samym, co używana w poprzednim zapisie funkcja będąca konstruktorem:


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

//w nowej składni

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

Dodawanie metod

Funkcje, które dodasz do danej klasy automatycznie trafią do prototypu obiektów, które będziesz tworzył na jej podstawie:


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

    eat() {
        console.log(this.name + " jem");
    }

    sleep() {
        console.log(this.name + " śpię");
    }
}
Class metody

W przeciwieństwie do obiektów budowanych na bazie funkcji konstruktorów metody takie nie będą uwzględniane, jeżeli po danym obiekcie zrobimy pętlę for in, a i w przypadku klas każda metoda ma swoją właściwość name, co może być kiedyś przydatne. Możesz to sprawdzić na przykładowej stronie.

Właściwości

Właściwości początkowe, które od razu pojawią się w obiektach budowanych na bazie danej klasy dodajemy zazwyczaj wewnątrz konstruktora:


class Animal {
    constructor(name) {
        this.name = name;
        this.legs = 4;
        this.type = "animal";
    }

    show() {
        console.log(`Zwierze nazywa się ${this.name} i ma ${this.legs} nóg`);
    }
}

const pet1 = new Animal("Koń");

Jeżeli dane właściwości nie wymagają przekazania wartości przy tworzeniu, możemy też je stworzyć bezpośrednio w ciele klasy:


//równoznaczne z powyższym kodem
class Car {
    years = 0;
    wheels = 4;

    ...
}

class Car {
    years = 0;
    wheels = 4;

    constructor(color) {
        this.color = color;
    }
}

//jest równoznaczne jest z

class Car {
    constructor(color) {
        this.years = 0;
        this.wheels = 4;
        this.color = color;
    }
}

Metody statyczne

Jeżeli stworzymy metody danej klasy, domyślnie trafią one do prototypu obiektów tworzonych na bazie tej klasy.


class Human {
    constructor(name) {
        this.name = name;
    }

    say() {
        console.log("Jestem człowiek");
    }
}

const ob = new Human("Marcin");
ob.say(); //"Jestem człowiek" - obiekt skorzystał z metody z prototypu

Możemy też tworzyć metody i właściwości statyczne. Nie są one dostępne dla pojedynczych instancji, ale możemy je w przyszłości uruchomić bezpośrednio poprzez daną klasę.
Takimi statycznymi funkcjonalnościami są najczęściej jakieś użyteczne funkcje, które będą zgrupowane w danej klasie.

Przykładami takich metod są Array.isArray(), które odpalamy by sprawdzić czy dana wartość jest tablicą, czy chociażby Object.getPrototypeOf() , która zwraca prototyp danego obiektu.


class Human {
    constructor(name) {
        this.name = name;
    }

    say() {
        console.log("Jestem człowiek");
    }

    static printInfo() {
        console.log("Ludzie są fajni");
    }
}

Human.printInfo(); //"Ludzie są fajni"

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

    static compareByName(a, b) {
        if (a.name < b.name) return -1;
        if (a.name > b.name) return 1;
        return 0;
    }

    static compareByAge(a, b) {
        return a.age - b.age;
    }
}

const users = [
    new User("Tomek", 10),
    new User("Ania", 35),
    new User("Beata", 20),
    new User("Monika", 20),
    new User("Karol", 22)
];

users.sort( User.compareByName );
console.log( users[0].name ); // Ania

users.sort( User.compareByAge );
console.log( users[0].name ); // Tomek

Wszelkie prawa zastrzeżone. Jeżeli chcesz używać jakiejś części tego kursu, skontaktuj się z autorem.
Aha - i ta strona korzysta z ciasteczek.