Class

Классы в JavaScript были введены в ECMAScript 2015 и представляют собой синтаксический сахар над существующим в JavaScript механизмом прототипного наследования.

Когда-то все писалось на прототипах Сейчас уже все пишется на классах

Метод constructor — специальный метод, необходимый для создания и инициализации объектов, созданных, с помощью класса.

class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
}

//  Экземпляр класса
const square = new Rectangle(10, 10);

// В РОДИТЕЛЯ выносим только самое необходимое
// наследоваться оно будет всем последующим

// с передачей аргументов (последовательно, по очереди)
class Person{
    constructor(name = 0, age){     // сюда передаются
        this.name = name;       // сюда присваиваются
        this.age = age;
    }
    // методы для класса
    // в большинстве случаев пишутся за конструктором
    sayName () {            // этот метод получается полиморфическим
        console.log(`My name: ${this.name}`)
    }
}

// экземпляр класса
// и передача аргументов ЯВНО
const p1 = new Person('Биба', 11)   // отсюда берутся

console.log("p1:", p1)
p1.sayName();


class Student extends Person {
    // последовательная передача аргументов (важна последовательность)
    constructor(name, age, group) {
        super(name, age)
        this.group = group;
    }
}
const s1 = new Student('Denis', 18, 'Dolphins')
// передача аргументов в виде одного объекта
// через деструктуризацию

class Person{
    constructor({ name, age} ){     // из объекта деструктурируем name и age и по ключам достаём
        this.name = name;       // сюда присваиваются
        this.age = age;
    }
    // методы для класса
    // в большинстве случаев пишутся за конструктором
}

const p1 = new Person({ name: 'Биба', age: 11}) // один аргумент в виде одного объекта (но несколько полей)




class Student extends Person {
    // через полную деструктуризацию (так не желательно!!!!)
        constructor({name, age, group}) {
            super({name, age})  //  лишний раз разворачиваем
            this.group = group;
        }
}



// А ТАК ВРОДЕ ТОЖЕ СРАБОТАЕТ
class Student extends Person { 
    constructor(options) {
        super(options)  /
    this.group = options.group  
    }
}
const s1 = new Student({name: 'Denis', age: 18, group: 'Dolphins'})

// передача аргументов через объект options
// без деструктуризации

class Person{
    constructor(options){     // входящий аргумент options - объект, и он один 
        this.name = options.name;       // а ключей несколько и к ним можно обращаться как к ключам (name и age)объекта options
        this.age = options.age || 0;    // значение по умолчанию через пайпы ||
        // есть еще нулевое слияние this.age = options.age ?? 0
        // оператор опциональной последовательности this.name = options?.name, тогда даже при const p1 = new Person() без передачи объекта в Person() - ошибки не будет (т.е. это проверки - существует ли options, как объект, и если не сущесвтует, тогда там не надо никакие name и age там искать, потому что это бесполезно)
    }

    birthDay() {    // метод
    console.log(`С днем рождения ${this.name}`)
    this.age += 1;  
    }
}

const p1 = new Person({ name: 'Биба', age: 11}) // один аргумент в виде одного объекта 
p1.birthday(); // возраст, который увеличиться в экземпляре класса p1

Наследование классов extends

class Person{
    constructor(options){
        this.name = options.name;
        this.age = options.age || 0;
    }

    birthDay() { 
    console.log(`С днем рождения ${this.name}`)
    this.age += 1;  
    }
}

class Student extends Person { // класс Student расширяется классом Person (мы сделали наследование всех методов Person + из super мы унаследовали весь конструктор родительский)
    constructor(options) {
        super(options)  //  наследование конструктора Person, передаем ОДНИМ объектом options
        // super является родительским конструктором, т.е. constructor(options) в class Person
        // и у нас будут заходить те же самые объекты (в данном случае объект options)
    this.group = options.group  // это поле не пойдет в родителя, используется только здесь
    }
}

const s1 = new Student({name: 'Denis', age: 18, group: 'Dolphins'})

// если мы хотим работать с options,
// то у нас будет только один option, как объект
// и в нем мы обращаемся к свойствам
// это правильный подход
// мы всё передаем в одном месте


// если мы хотим передавать несколько аргументов
// значит это уже будет не в виде объекта
// можно еще так
// но так можно запутаться
// и так лучше не делать


class Student extends Person {
    constructor(options, group) {
        super(options)
    this.group = group
    }
}

const s1 = new Student({name: 'Denis', age: 18 }, 'Dolphins')


Публичные поля Публичные поля доступны на экземпляре класса (самих классов) Мы можем указать вне конструктора


class Person{
    human = 'Im human'
    constructor(name, age){
        this.name = options.name;
        this.age = options.age;
    }
}

class Student extends Person {

    bootcamp = 'BName'  // строго невходящее, оно ниоткуда не приходит, но можно наследовать (но только таким, оно неизменяемо)

    constructor(name, age, group) {
        super(name, age)
        this.group = group;
    }
}
const s1 = new Student('Denis', 18, 'Dolphins')
console.log(s1) // human: 'Im human', name: 'Denis', age: 18, bootcamp: 'BName', group: 'Dolphins'
// т.е. последовательность такая: сначала идёт всё из super, потом идут публичные поля, а потом идет группа

Приватные поля (в рамках инкапсуляции)

Раньше: this._brand = 'BrandName' Сейчас: #brand = 'BrandName'



class Student extends Person {
    constructor(name, age, group) {
        super(name, age)
        this.group = group;
    }
}
const s1 = new Student('Denis', 18, 'Dolphins')
const s2 = new Student('Denis', 18, 'Wolves')
const s3 = new Student('Denis', 18, 'Wolves')
const s4 = new Student('Denis', 18, 'Dolphins')


// хотим отфильтровать по группам
const arr = [s1, s2, s3, s4]
const filterByGroup = arr.filter((el) => el.group === 'Dolphins') //  отфильтрует по group

А теперь тоже самое через статические методы


class Student extends Person {
    constructor(name, age, group) {
        super(name, age)
        this.group = group;
    }
    
    // Статические методы вызываются НА САМОМ КЛАССЕ, А НЕ НА ЕГО ЭКЗЕМПЛЯРЕ
    static filterByGroup (students, group) {
        const arr = students.filter((el) => el.group === group)
        if (arr.length) {
            return arr
        } else { return 'Студенты не найдены'}
    }
}

// экземпляры
const s1 = new Student('Denis', 18, 'Dolphins')
const s2 = new Student('Denis', 18, 'Wolves')
const s3 = new Student('Denis', 18, 'Wolves')
const s4 = new Student('Denis', 18, 'Dolphins')


// хотим отфильтровать по группам
const arr = [s1, s2, s3, s4]
const filterByGroup = arr.filter((el) => el.group == 'Dolphins') //  отфильтрует по group

// вызовем статический метод
console.log(Student.filterByGroup(arr, 'Dolphins'))

ПРИМЕРЫ СТАТИЧЕСКИХ МЕТОДОВ они вызываются не на каком-то конкретном экземпляре, а на самом классе непосредственно Number.isNaN Array.isArray Object.keys Object.value Object.assign


class Animal {
    constructor(name) {
    this.name = name || 'NoName';
  }

  speak() {
    console.log(`${this.name} издаёт звук.`);
  }
}

// вызовем метод на экземпляре класса
const animal1 = new Animal('Sharik')
animal.speak();

// через деструктуризацию
class Animal {
    constructor({ name, age} ) {
    this.name = name || 'NoName';
    this.age = age || 0;
  }
}

// через options (без деструктуризации)
class Animal {
    constructor(options) {
    this.name = options?.name || 'NoName';
    this.age = options?.age || 0;
  }
}

// наследование

class Dog extends Animal {
  constructor(name) {
    super(name); // вызывает конструктор super класса и передаёт параметр name
  }

  speak() {
    console.log(`${this.name} лает.`);
  }
}


Last updated