Для новичка в программировании понимание классов в Javascript может оказаться довольно сложным. В сети много источников, но большинство из них говорят с точки зрения старшего разработчика, что предполагает множество знаний, которых нет в голове у нового разработчика. Вот почему я пишу эту статью: представить классы в Javascript таким образом, чтобы их было легко понять.

Большая часть этих знаний получена благодаря Стивену Майе. Если бы не он, у меня до сих пор были бы проблемы с пониманием концепции. Так что, если вы предпочитаете смотреть видео, а не читать, вы можете проверить его плейлист на эту тему, он исключительный: https://www.youtube.com/playlist?list=PLtwj5TTsiP7uTKfTQbcmb59mWXosLP_7S

В этом посте я сначала расскажу о классах, затем расскажу о статических методах и статических свойствах и в заключение кратко расскажу о расширениях и ключевых словах super.

### Классы
Классы в Javascript очень и очень похожи на конструкторы объектов. Так что, если вы знакомы с ними, они кусок пирога. Они по-прежнему создают прототип чего-то, чтобы мы могли использовать один и тот же код снова и снова вместо того, чтобы вводить его вручную. Они просто предоставляют нам некоторые новые функции, которых не было в прежних версиях. Итак, без лишних слов, давайте создадим наш первый класс:

```
class Bird {
конструктор (имя, возраст){
this.name=имя;
this.age=возраст;
this.canFly= true ;
}
}
```
Итак, в нашем классе слов есть метод-конструктор. Аргументы должны принимать имя нашей птицы, ее возраст, и может ли она летать или нет. ‹br›

Этот метод конструктора будет немедленно вызван, как только мы вызовем его через ключевое слово «new». Мы используем ключевое слово «новое» для создания экземпляра класса. Давайте создадим экземпляр с именем birdLarry:
```
const birdLarry= new Bird («Ларри», 4);
```
Понимаете, для создания нового класса Например, мы определяем переменную (birdLarry) и после знака равенства пишем ключевое слово «new», за которым следует имя класса, который мы хотим вызвать (в нашем случае Bird). Затем добавляем аргументы: имя экземпляра Bird и его возраст.‹br›

Теперь, если мы запишем `birdLarry.name;` в нашу консоль, результатом будет «Larry». Если бы мы написали `birdLarry.age`, то получили бы на выходе число 4. И если бы мы написали `birdLarry.canFly`, вывод был бы «true».

Все идет нормально. ‹br›

Давайте добавим еще несколько методов в наш класс Bird.

```
class Bird {
конструктор (имя, возраст){
this.name=имя;
this.age=возраст;
this.canFly= true ;
}
nameAge() {
return `${this.name} ${this.age} лет`;
}
}
```
Что мы здесь делали? Видите ли, этот метод nameAge даст информацию о нашем экземпляре Bird. Например, если бы мы написали ‹br›
`birdLarry.nameAge();`, вывод был бы «Ларри 2 года». Тем не менее, супер просто. Но что, если бы мы захотели изменить имя нашей птицы? Скажем, от Ларри до Растяпы? а также изменить свой возраст тоже? Потому что я чувствую, что птица по имени Неуклюжий должна быть совсем молодой. Добавим наши методы:

```
class Bird {
конструктор (имя, возраст){
this.name=имя;
this.age=возраст;
this.canFly= true ;
}
nameAge() {
return `${this.name} ${this.age} лет`;
}
setName(name) {
this.name = имя;
}

setAge(age) {
this.age = age;
}
}
```
С помощью этого недавно добавленного кода мы можем изменить имя и возраст нашей птицы. Таким образом, если бы мы написали `birdLarry.setName(“Clumsy”);` и вызвали бы `birdLarry.name;`, вывод был бы “Clumsy”, так как мы изменили исходное имя экземпляра нашего класса. Кроме того, поскольку Clumsy должен быть немного моложе, мы хотели бы также изменить его возраст, написав `birdLarry.setAge(2)` в нашей консоли. Теперь всякий раз, когда мы вызываем `birdLarry.age`, результатом будет 2.

Хафф, рад, что мы рассмотрели это, потому что то, что будет дальше, намного интереснее, чем эти основы :)
### Статические методы
Что, если мы хотим добавить методы ** не для экземпляров **, а * *для самого класса?** Что ж, с функцией классов ES6 мы можем сделать это очень просто! Итак, давайте возьмем наш класс Bird и посмотрим, что мы можем сделать с ним, используя статические методы (я не буду писать дополнительные методы для простоты и объема):

```
class Bird {
static Kingdom(){
return «Animalia»;
}
static KingdomSentence () {
return `Птицы принадлежат в королевство ${this.kingdom()}`;
}

конструктор (имя, возраст){
this.name=name;
this.age=age;
this.canFly= true;
}
}
```
Ууууууу, притормози, приятель, что там происходит? Что ж, мы добавили два статических метода: первый возвращает, к какому биологическому царству принадлежат птицы (Animalia, потому что они действительно животные), а второй возвращает предложение, используя царство. Вы видите, что я использовал здесь ключевое слово «это». Это интересная часть статического метода: хотя ключевое слово this обычно ссылается на экземпляр класса, если оно находится в обычном методе, внутри статического метода оно указывает на сам класс. Подождите, что это значит? Потерпи немного.

Теперь, если мы запишем входные данные `birdLarry.kingdom()`, вывод будет примерно таким: `Uncaught TypeError: birdsLarry.kingdom не является функцией в ‹anonymous›:1:11` Uf. Почему?

Как я уже упоминал в начале этого раздела, статические методы работают с самим классом, а не с его экземплярами. И наш `birdLarry` является экземпляром класса `Bird`. Таким образом, статический метод не будет работать с ним. Вместо этого статический метод будет работать только с классом `Птица`. Вот так:‹br›
`Bird.kingdom()` вернет `”Animalia”`. И если бы мы написали `Bird.kingdomSentence()`, он вернул бы `”Птицы принадлежат царству Animalia”`. Довольно круто, да?‹br›
Теперь есть еще один способ написания этих статических методов. Их называют статическими свойствами. Давайте посмотрим, как они работают.
### Статические свойства
Свойства, по сути, не являются функцией. Например, это строки, числа, логические значения и т. д. Мы можем написать вышеуказанные статические методы как таковые:

```
class Bird {
static Kingdom= «Animalia»;

static KingdomSentence=`Птицы принадлежат королевству ${this.kingdom}`;

конструктор (имя, возраст){
this.name=name;
this.age=age;
this.canFly= true;
}
}
```
Видишь, что мы там делали? Мы убрали всевозможные скобки и ключевое слово return. Мы также взяли скобки, указывающие на вызов функции при использовании `this.kingdom`. Этот способ работает так же, как и предыдущий, но чище. Что произойдет, если мы напишем `Bird.kingdom()`?

Ну, мы бы получили такую ​​ошибку: `Uncaught TypeError: Bird.kingdom не является функцией в ‹anonymous›:1:6`, потому что теперь это свойства, а не функции! Итак, мы будем называть их следующим образом:
`Bird.kingdom;`, который вернет `”Animalia”`, и ‹br›
`Bird.kingdomSentence`, который вернет `”Птицы принадлежат царство Анималия».

Хорошо, если с этим у нас все в порядке, давайте перейдем к финалу, и самый удобный метод, который у нас есть в рукаве.
### Расширяет и Супер

Сейчас все круто. Мы можем написать всего один кусок кода и создать много-много разных его экземпляров. Но что, если мы столкнемся с ситуацией, когда захотим создать еще один класс, почти такой же, как наш класс Bird? И, очевидно, мы не хотим повторяться, снова и снова вводить очередной фрагмент кода. Что бы мы сделали?

Ну, мы бы использовали ключевое слово extends, чтобы преодолеть эту досадную трудность.

Теперь предположим, что мы хотим создать новый класс Penguin. Поскольку пингвины — птицы, они делят почти все имущество с другими птицами. Я говорю почти, потому что пингвины не умеют летать, а BBC меня не одурачит :) https://www.youtube.com/watch?v=9dfWzp7rYR4&ab_channel=BBC

В любом случае, со следующим кодом наш новый класс Penguin возьмет все, что есть у класса Bird. Вы видите супер ключевое слово там? Он берет методы name и age из исходного класса. Я также убедился, что canFly указывает на «false» :)

```
класс Penguin расширяет Bird {
конструктор (имя, возраст){
super(имя, возраст);
this.canFly=false;

}
}
```
Что случилось? Чтобы увидеть, что происходит, давайте создадим новый экземпляр класса Penguin и назовем его coldFeet:

`const coldFeet= новый пингвин ("ColdFeet", 3);`

Итак, наш новый пингвин, Холодноногий, может получить доступ ко всему, что есть у нашей птицы Ларри! Если бы мы записали `coldFeet.age`, вывод был бы 3. Если бы мы написал `coldFeet.canFly`, вывод был бы **false**. Почему? Очевидно, потому что мы дали понять, что пингвины не умеют летать :) А другие способы? Например, что произойдет, если мы зарегистрируем `coldFeet.nameAge();`?

Правильно, вывод будет: «ColdFeet 3 года», потому что, опять же, класс Penguin разделяет все с классом Bird!

Теперь наш экземпляр Penguin делит все с нашим экземпляром Bird. Но как насчет самого класса Penguin? Будут ли у него те же статические методы, что и у класса Bird?

Как вы можете видеть из моего выбора формулировки, это так :)

Допустим, мы использовали статические свойства при определении нашего класса Bird. Если бы мы написали «Penguin.kingdom», вывод был бы «Animalia».

А если бы мы написали `Penguin.kingdomSentence`, вывод был бы `”Птицы принадлежат царству Animalia” (потому что пингвины – это птицы, глупышка!)

### Заключение

В общем, именно так используются классы, насколько я понимаю, в Javascript (ES6). Они классные и функциональные. Надеюсь, мне удалось максимально ясно изложить свои мысли. И, для более старших разработчиков, если вы обнаружите ошибку, пожалуйста, не стесняйтесь сообщить мне! Я хотел бы увидеть свои ошибки!

Всего наилучшего и удачного кодирования :)