Использование классов в JavaScript: от основ до продвинутых примеров
Основы классов в JavaScript
Синтаксис class появился в ECMAScript 2015 и предлагает наиболее понятный способ реализации объектно-ориентированного подхода. Класс объявляется с помощью ключевого слова class и содержит конструктор, методы, геттеры/сеттеры и статические свойства.
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
greet() {
return `Привет, меня зовут ${this.name}`;
}
static isAdult(age) {
return age >= 18;
}
}Js class (классы в javascript)
Конструктор вызывается при создании экземпляра оператором new. Методы, объявленные внутри класса, автоматически попадают в прототип, а статические методы принадлежат самому классу.
const alice = new Person('Алиса', 25);
console.log(alice.greet()); // Привет, меня зовут Алиса
console.log(Person.isAdult(25)); // trueТипичные ошибки:
- Забыть
newпри вызове конструктора – в строгом режиме это вызывает TypeError. - Потеря контекста
thisпри передаче метода как колбэка. Решение – стрелочная функция в конструкторе илиbind.
// Ошибка: this будет undefined
const greet = alice.greet;
greet(); // TypeError: Cannot read properties of undefined (reading 'name')// Исправление
class Person {
constructor(name) {
this.name = name;
this.greet = () => `Привет, ${this.name}`;
}
}Как создать объект с методами без синтаксиса class?
До ES5 использовались функции-конструкторы и прототипное наследование. Этот подход остаётся рабочим, но уступает классам в читаемости.
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.greet = function() {
return `Привет, меня зовут ${this.name}`;
};
Person.isAdult = function(age) {
return age >= 18;
};Проблемы: необходимость вручную управлять прототипом, отсутствие чёткого синтаксиса для статических свойств, сложности с наследованием.
Забывание new – свойства запишутся в глобальный объект. Исправление: проверка if (!(this instanceof Person)) return new Person(name, age);
Как сделать фабричную функцию вместо класса?
Фабрики возвращают объект без использования new. Удобны для создания объектов с приватными данными через замыкания.
function createPerson(name, age) {
return {
name,
age,
greet() {
return `Привет, меня зовут ${name}`;
}
};
}
const bob = createPerson('Боб', 30);Отсутствует наследование через прототип – каждый экземпляр копирует методы, что увеличивает расход памяти. Применяется для простых объектов или когда нужна истинная инкапсуляция.
instanceof – результат всегда false.Как использовать классовые выражения?
Классы можно объявить как выражения, а не декларации. Это позволяет, например, динамически создавать классы или передавать их как аргументы.
const Animal = class {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} издаёт звук`);
}
};
const dog = new Animal('Собака');
dog.speak(); // Собака издаёт звукИмя классового выражения может быть опущено или задано только для внутреннего использования. Используется в паттерне «Примесь» (mixin) или при создании анонимных классов.
class – сложнее определить источник ошибки. Рекомендуется давать имена выражениям.// Миксины: расширение функциональности через примеси
const sayMixin = {
sayHi() {
console.log(`Привет, ${this.name}`);
}
};
class User {
constructor(name) {
this.name = name;
}
}
Object.assign(User.prototype, sayMixin);
const user = new User('Елена');
user.sayHi(); // Привет, ЕленаВывод: Привет, Елена
// Наследование встроенных классов
class MyArray extends Array {
first() {
return this[0];
}
last() {
return this[this.length - 1];
}
}
const arr = new MyArray(1, 2, 3);
console.log(arr.first()); // 1
console.log(arr.last()); // 3
console.log(arr instanceof Array); // true1 3 true
// Статические блоки инициализации (ES2022)
class Config {
static {
this.defaultTimeout = 5000;
this.defaultUrl = 'https://api.example.com';
}
}
console.log(Config.defaultTimeout); // 50005000
// Приватные поля (ES2022)
class BankAccount {
#balance = 0;
deposit(amount) {
if (amount < 0) throw new Error('Неверная сумма');
this.#balance += amount;
}
getBalance() {
return this.#balance;
}
}
const acc = new BankAccount();
acc.deposit(100);
console.log(acc.getBalance()); // 100
// console.log(acc.#balance); // SyntaxError: Private field100
// Проверка принадлежности через instanceof
class Animal {}
class Dog extends Animal {}
const dog = new Dog();
console.log(dog instanceof Dog); // true
console.log(dog instanceof Animal); // true
console.log(dog instanceof Object); // truetrue true true