Классы
Зачем это нужно
Допустим, в игре сто врагов. У каждого есть имя, здоровье, атака и одинаковые действия: «ударить», «получить урон». Писать сто объектов вручную — долго. Класс — это чертёж: по нему можно создать сколько угодно объектов одного вида. Такой объект называют экземпляром класса.
На классах построены многие библиотеки, а встроенные Map, Set, Date, Error — тоже классы.
Объявление класса
class User {
constructor(name, age) {
this.name = name;
this.age = age;
}
greet() {
return `Привет, я ${this.name}`;
}
}
const anya = new User("Аня", 15);
const timur = new User("Тимур", 17);
console.log(anya.greet());
console.log(timur.age);
Вывод:
Привет, я Аня
17
class User { … }— объявление класса. Имена классов пишут с большой буквы.constructor— особый метод, который вызывается при создании объекта. В нём задают свойства.this— создаваемый объект.this.name = nameкладёт значение в его свойствоname.new User(…)— создать экземпляр. Безnewбудет ошибка.- Методы (
greet) пишутся внутри класса без словаfunctionи без запятых между ними.
Методы меняют состояние
class Counter {
constructor() {
this.value = 0;
}
increase(step = 1) {
this.value += step;
return this.value;
}
}
const c = new Counter();
c.increase();
c.increase(5);
console.log(c.value);
Вывод:
6
Каждый экземпляр хранит свои свойства: два разных Counter считают независимо.
Геттеры и сеттеры
Геттер — метод, который читается как свойство, без скобок. Сеттер — метод, который срабатывает при присваивании.
class Temperature {
constructor(celsius) {
this.celsius = celsius;
}
get fahrenheit() {
return this.celsius * 9 / 5 + 32;
}
set fahrenheit(f) {
this.celsius = (f - 32) * 5 / 9;
}
}
const t = new Temperature(25);
console.log(t.fahrenheit);
t.fahrenheit = 212;
console.log(t.celsius);
Вывод:
77
100
Геттер удобен для вычисляемых значений и для «только чтения»: если сеттера нет, присвоить значение не получится.
Приватные поля
Поле с # в начале имени видно только внутри класса:
class Wallet {
#money = 0;
add(x) { this.#money += x; }
get total() { return this.#money; }
}
const w = new Wallet();
w.add(50);
console.log(w.total);
Вывод:
50
Снаружи w.#money — синтаксическая ошибка. Так защищают данные от случайного изменения. По
старинке «внутренние» поля помечают подчёркиванием (this._money) — это просто договорённость.
Наследование: extends и super
Класс может наследовать другой: получить все его свойства и методы и добавить свои.
class Animal {
constructor(name) {
this.name = name;
}
speak() {
return `${this.name} издаёт звук`;
}
sleep() {
return `${this.name} спит`;
}
}
class Cat extends Animal {
speak() {
return `${this.name} мяукает`;
}
}
const murka = new Cat("Мурка");
console.log(murka.speak()); // свой метод
console.log(murka.sleep()); // унаследованный
console.log(murka instanceof Cat, murka instanceof Animal);
Вывод:
Мурка мяукает
Мурка спит
true true
Если у дочернего класса свой constructor, в нём первым делом нужно вызвать super(...) —
конструктор родителя:
class Student extends Animal {
constructor(name, school) {
super(name); // родитель запишет this.name
this.school = school;
}
speak() {
return super.speak() + " и отвечает урок"; // вызов метода родителя
}
}
console.log(new Student("Тимур", "№5").speak());
Вывод:
Тимур издаёт звук и отвечает урок
Статические методы
static — метод самого класса, а не экземпляров: Math.max устроен похоже.
class MathUtil {
static square(x) { return x * x; }
}
console.log(MathUtil.square(7));
Вывод:
49
Как это работает внутри
Методы класса не копируются в каждый объект — они лежат в одном общем месте, прототипе
(User.prototype). Когда ты вызываешь anya.greet(), JS ищет greet сначала в самом объекте, не
находит и идёт в прототип. При наследовании прототипы выстраиваются в цепочку: Cat.prototype →
Animal.prototype → Object.prototype. Поиск идёт по цепочке, пока метод не найдётся. Поэтому
murka.sleep() работает, хотя в Cat его нет.
Частые ошибки
- Без
new.User("Аня")→TypeError: Class constructor User cannot be invoked without 'new'. - Без
this.name = nameв конструкторе ничего не сохраняет в объект. Нужноthis.name = name. - Забыли
super(). В дочернем конструкторе обращение кthisдоsuper(...)— ошибка. - Запятые между методами. В классе методы пишутся без запятых (в отличие от объекта).
- Геттер со скобками.
acc.balance()→ ошибка «is not a function». Геттер читают без скобок:acc.balance.
Шпаргалка
| Что | Как |
|---|---|
| Класс | class Name { constructor(a) { this.a = a; } } |
| Экземпляр | const x = new Name(1); |
| Метод | go() { return this.a; } |
| Геттер / сеттер | get total() {…}, set total(v) {…} |
| Приватное поле | #secret = 0; |
| Наследование | class B extends A { … } |
| Родитель | super(…) в конструкторе, super.method() |
| Статический метод | static create() {…} |
| Проверка | x instanceof Name |