webroad.online
  1. 1Веб
  2. 2HTML
  3. 3CSS
  4. 4JavaScript
  5. 5TypeScript
  6. 6Git
  7. 7Инструменты
  8. 8React
  9. 9Стейт-менеджмент
  10. 10Next.js
  11. 11Формы
  12. 12Данные и бэкенд
  13. 13SEO
  14. 14Tailwind CSS
  15. 15Анимации
  16. 16Тестирование
  17. 17Архитектура
JavaScript · Урок 12 из 17

Классы и прототипы

class, приватные поля, геттеры, extends и что под капотом.

Обновлено

Что такое класс

Класс — это шаблон для создания однотипных объектов. Он один раз описывает, какие у них данные (свойства) и поведение (методы); затем вы создаёте сколько угодно экземпляров через new.

class Account {
  constructor(owner) {          // выполняется при new — инициализирует объект
    this.owner = owner
    this.balance = 0
  }

  deposit(amount) {             // метод — общее поведение всех счетов
    this.balance += amount
  }
}

const a = new Account('Ana')    // экземпляр
const b = new Account('Ivan')   // другой экземпляр со своими данными
a.deposit(100)

Аналогия: класс — это формочка, экземпляры — печенье.

Части класса — виды членов

Член Синтаксис Принадлежит Когда
публичное поле count = 0 каждому экземпляру данные, видимые снаружи
приватное поле #balance = 0 каждому экземпляру, недоступно снаружи внутренние защищённые данные
метод deposit() {} общий для всех экземпляров поведение
геттер / сеттер get total() {} / set total(v) {} экземпляру вычисляемое значение, читаемое как свойство
static static from(json) {} классу, а не экземпляру фабрики, константы, хелперы
class Account {
  #balance = 0                      // приватное — acc.#balance даёт SyntaxError
  static currency = 'RUB'           // Account.currency

  constructor(owner) { this.owner = owner }

  deposit(amount) {
    if (amount <= 0) throw new Error('Неверная сумма')
    this.#balance += amount
    return this                     // позволяет цепочку: acc.deposit(1).deposit(2)
  }

  get balance() { return this.#balance }   // acc.balance — без скобок

  static fromJSON({ owner }) { return new Account(owner) }
}

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

extends создаёт класс, который берёт всё у другого и что-то добавляет или меняет:

class Savings extends Account {
  constructor(owner, rate) {
    super(owner)                // вызывает конструктор родителя — обязательно до this
    this.rate = rate
  }

  addInterest() { this.deposit(this.balance * this.rate) }
}

Прототипы — что под капотом

Классы — «синтаксический сахар» над прототипами. У каждого объекта есть скрытая связь с другим объектом (его прототипом). Если запросить свойство, которого нет у объекта, JS ищет его в прототипе, затем в прототипе прототипа — это цепочка прототипов.

a.deposit                                 // не у a, найден в Account.prototype
Object.getPrototypeOf(a) === Account.prototype   // true
a instanceof Account                      // true — Account.prototype есть в цепочке

Поэтому методы общие (один deposit в памяти на все счета), а [].map работает на любом массиве (он лежит в Array.prototype).

Классы или функции + объекты

Классы Функции + простые объекты
Защищённое внутреннее состояние #private замыкание
Наследование extends композиция (комбинируете функции)
this да, со всеми ловушками не нужен
В современном React только error boundaries всё: компоненты, хуки

Когда использовать классы во фронтенде

  • Да: свои ошибки (class HttpError extends Error), API-клиент / SDK, структуры данных (очередь, кэш), интеграция с библиотеками на классах.
  • Нет: React-компоненты (сегодня это функции), простые данные (хватит литерала объекта).
  • Предпочитайте композицию (маленькие части вместе) глубоким иерархиям наследования — A extends B extends C extends D трудно менять.

Коротко

  • Класс = шаблон; new создаёт экземпляры; constructor инициализирует.
  • Поля #private, геттеры, static, extends + super.
  • Под капотом — прототипы. В React почти всегда функции.

Официальные источники

Упражнения

Была ли страница полезной?

Один клик — без регистрации.