Классы: базовый синтаксис #
class — объявление «типа» объекта с конструктором и методами. Синтаксис похож на классы в других языках, но в JavaScript это обёртка над прототипами: методы попадают на prototype, наследование строится через цепочку прототипов.
Объявление класса #
class Lesson {
constructor(title, durationMin) {
this.title = title
this.durationMin = durationMin
this.done = false
}
complete() {
this.done = true
return this
}
summary() {
const status = this.done ? 'пройден' : 'в процессе'
return `${this.title} (${this.durationMin} мин) — ${status}`
}
}
const lesson = new Lesson('Замыкания', 25)
lesson.complete().summary()
// "Замыкания (25 мин) — пройден"
new обязателен — вызов Lesson() без new в классах выбросит ошибку.
constructor #
Специальный метод, который инициализирует экземпляр. В классе может быть только один constructor. Если его не написать, используется пустой конструктор по умолчанию.
class UserProgress {
constructor(userId) {
if (!userId) {
throw new Error('userId обязателен')
}
this.userId = userId
this.completedLessons = []
}
}
Логику валидации и значения по умолчанию держите в конструкторе; тяжёлую работу выносите в отдельные методы.
Методы экземпляра #
Методы в теле класса — короткая запись для функций на прототипе:
class Cart {
constructor() {
this.items = []
}
add(item) {
this.items.push(item)
}
total() {
return this.items.reduce((sum, { price }) => sum + price, 0)
}
}
const cart = new Cart()
cart.add({ title: 'JSFlow Sticker', price: 150 })
cart.total() // 150
Стрелочные функции как поля класса (total = () => {}) создают свойство на каждом экземпляре — для обычных методов предпочтительны короткие методы в теле класса.
Геттеры и сеттеры #
Выглядят как свойства, но вызывают функции:
class StudyPlan {
constructor(lessons) {
this.lessons = lessons
}
get count() {
return this.lessons.length
}
set count(value) {
throw new Error('count только для чтения')
}
get estimatedHours() {
const minutes = this.lessons.reduce((s, l) => s + l.durationMin, 0)
return Math.round((minutes / 60) * 10) / 10
}
}
const plan = new StudyPlan([
{ title: 'Операторы', durationMin: 20 },
{ title: 'Циклы', durationMin: 30 },
])
plan.count // 2
plan.estimatedHours // 0.8
Геттеры удобны для вычисляемых значений без вызова () в шаблонах.
Class expression #
Класс можно присвоить переменной или передать как значение:
const Formatter = class {
constructor(locale) {
this.locale = locale
}
formatDate(date) {
return date.toLocaleDateString(this.locale)
}
}
const ru = new Formatter('ru-RU')
ru.formatDate(new Date('2026-07-14')) // "14.07.2026"
Именованные class expression (class Name {}) видны только внутри выражения — полезно для отладки в стеке.
Подъём (hoisting) #
В отличие от function, объявление class не поднимается:
// ReferenceError: Cannot access 'Course' before initialization
// const c = new Course()
class Course {
constructor(name) {
this.name = name
}
}
Объявляйте классы до использования или используйте class expression после присваивания.
Отличия от объекта-литерала #
class + new | объект { } | |
|---|---|---|
| создание | new Lesson() | const o = { } |
| прототип | настраивается цепочкой | Object.prototype или Object.create |
| наследование | extends | вручную через прототип |
instanceof | да | зависит от цепочки |
Классы уместны, когда много экземпляров с общим поведением; литерал — для единичных конфигов и простых структур.
Частые ошибки #
- Забыли
new—TypeError: Class constructor Lesson without new. - Метод-стрелка в классе для наследования — поле экземпляра, не на прототипе; дочерние классы не переопределяют его через
superв прототипной цепочке. - Тяжёлая работа в constructor — блокирует создание; используйте ленивую инициализацию.
- Сеттер без валидации — любое присваивание ломает инварианты объекта.
Итог #
classзадаёт конструктор и методы; под капотом — функция и прототип.- Методы в теле класса общие для экземпляров через
prototype. - Геттеры и сеттеры оформляют вычисляемые и контролируемые свойства.
- Классы не hoisting — объявляйте до создания экземпляров.