Объектно-ориентированное программирование и OOP в JavaScript

Концепции
- Абстракция
- Инкапсуляция
- Наследование
- Полиморфизм
Абстракция
Абстракция позволяет нам сосредоточиться на том, что делает объект, а не на том, как он это делает.
В TypeScript реализованы абстрактные классы ключевым словом abstract
.
От абстрактного класса нельзя создать экземпляр. Пример из Revuud: абстрактный класс — User, конкретные классы — Talent и Admin.
Цель — не дублировать код
ссылка на пример с абстрактным классом
Инкапсуляция
Это разделение интерфейсов на внутренний и внешний — приватные и публичные свойства/методы.
Цель — ограничить внешних пользователей от изменений внутреннего интерфейса, чтобы ничего не сломали внутри извне.
Есть конвенция называть приватные свойства начиная с _
.
На уровне языка реализуется символом #
:
class Person { #_privateField: 'value' #_privateMethod () {} } new Person()._privateField// undefined
Наследование
Наследование классов – это способ расширения одного класса другим классом.
Цель — не дублировать код и экономить память, расширять уже существующий функционал.
Полиморфизм
Это способность вызывать один и тот же метод для разных объектов, и при этом каждый объект реагирует по-своему. Чтобы это произошло, полиморфизм использует наследование.
Пример, демонстрирующий все 4 концепции
abstract class User { abstract firstName: string; abstract lastName: string; abstract sendInvite(): void; //! 1. принцип абстракции (нет реализации, только объявление) get fullName() { // неабстрактный метод с логикой return this.firstName + this.lastName; // в отличие от интерфейса здесь можно писать логику } } new User(); // Ошибка, нельзя создать экземпляр абстрактного класса class Admin extends User { //! 3. принцип наследования (расширяем конкретный класс от абстрактного) firstName; lastName; constructor(firstName: string, lastName: string) { super(); this.firstName = firstName; this.lastName = lastName; } get fullName() { //! 4. принцип полиморфизма (переопределяем геттер родителя, чтобы он работал по-другому) return this.firstName + " last name is NDA for admins"; } sendInvite() { //! 4. принцип полиморфизма (реализуем абстрактный метод по-разному в 2 дочерних классах) const author = this.fullName; alert({ type: "admin", author }); //фиктивная функция отправки } } class Talent extends User { //! 3. принцип наследования (расширяем конкретный класс от абстрактного) firstName; lastName; #age: number; //2. инкапсуляция (приватное поле) constructor(firstName: string, lastName: string, age: number) { super(); this.firstName = firstName; this.lastName = lastName; this.#age = age; } sendInvite() { //! 4. принцип полиморфизма (реализуем абстрактный метод по-разному в 2 дочерних классах const author = super.fullName; //! 3. наследование, вызываем геттер родительского класса alert({ type: "talent", author }); //фиктивная функция отправки } } const john = new Talent("John", "Smith", 30); //! 2. инкапсуляция (приватное поле недоступно вне класса Talent) john.#age; // SyntaxError