ООП в JavaScript: принципы и реализация
Что такое ООП и зачем оно в JavaScript? 🤔
Объектно-ориентированное программирование (ООП) — это парадигма, где код организуется вокруг объектов и их взаимодействий. В JavaScript ООП реализовано через прототипы, но с ES6 появился и более привычный синтаксис классов.
Почему это важно?
ООП помогает:
- Упростить поддержку кода 🛠️
- Уменьшить дублирование (DRY — Don’t Repeat Yourself) ♻️
- Создавать более предсказуемые и масштабируемые приложения 🏗️
Четыре кита ООП 🐋
1. Инкапсуляция
Скрытие деталей реализации от внешнего мира.
Пример: методы объекта работают с его внутренними свойствами, но не дают к ним прямой доступ.
class User {
constructor(name) {
this._name = name; // _name — условно приватное свойство
}
get name() {
return this._name.toUpperCase(); // Контролируем доступ
}
}
const danila = new User('Danila');
console.log(danila.name); // 'DANILA' — доступ через геттер
💡 В JavaScript нет настоящей приватности (до ES2022), но
_в имени свойства — это договорённость, что оно «внутреннее».
2. Наследование
Создание новых классов на основе существующих.
В JavaScript это работает через цепочку прототипов или extends.
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} издает звук.`);
}
}
class Dog extends Animal {
speak() {
console.log(`${this.name} лает: Гав!`); // Переопределение метода
}
}
const rex = new Dog('Рекс');
rex.speak(); // 'Рекс лает: Гав!'
3. Полиморфизм
Один интерфейс — множество реализаций. Объекты разных классов могут использовать одинаковые методы.
class Cat extends Animal {
speak() {
console.log(`${this.name} мяукает: Мяу!`);
}
}
const animals = [new Dog('Бобик'), new Cat('Мурзик')];
animals.forEach(animal => animal.speak());
// Бобик лает: Гав!
// Мурзик мяукает: Мяу!
4. Абстракция
Упрощение сложных систем путем выделения ключевых концепций.
class CoffeeMachine {
constructor() {
this._waterAmount = 0;
}
addWater(amount) {
this._waterAmount += amount;
console.log(`Добавлено воды: ${amount} мл`);
}
_boilWater() { // «Приватный» метод
console.log('Кипятим воду...');
}
makeCoffee() {
this._boilWater();
console.log('Ваш кофе готов! ☕');
}
}
Пользователь работает только с addWater и makeCoffee, не зная о внутренних процессах.
Классы vs Прототипы 🥊
До ES6 ООП в JavaScript строилось на прототипах. Классы — это «синтаксический сахар».
Прототипный пример:
function User(name) {
this.name = name;
}
User.prototype.sayHi = function() {
console.log(`Привет, я ${this.name}!`);
};
const user = new User('Данила');
user.sayHi(); // Привет, я Данила!
То же через класс:
class User {
constructor(name) {
this.name = name;
}
sayHi() {
console.log(`Привет, я ${this.name}!`);
}
}
🔥 Важно: Под капотом классы всё равно используют прототипы. Это знание поможет при отладке!
Статические методы и свойства 🏛️
Принадлежат классу, а не экземплярам. Полезны для утилит.
class MathUtils {
static PI = 3.14159; // Статическое свойство
static square(x) {
return x * x;
}
}
console.log(MathUtils.square(5)); // 25
console.log(MathUtils.PI); // 3.14159
Практика: пишем класс для интернет-магазина 🛒
class Product {
constructor(name, price) {
this.name = name;
this.price = price;
}
applyDiscount(discount) {
return this.price * (1 - discount);
}
}
class Cart {
constructor() {
this.items = [];
}
addItem(product, quantity = 1) {
this.items.push({ product, quantity });
}
getTotal() {
return this.items.reduce(
(sum, item) => sum + item.product.price * item.quantity,
0
);
}
}
// Использование
const iPhone = new Product('iPhone 15', 999);
const cart = new Cart();
cart.addItem(iPhone, 2);
console.log(cart.getTotal()); // 1998
Итог: когда использовать ООП? 🎯
- 🏗️ Сложные системы с чёткими сущностями (например, интернет-магазин).
- 🔄 Повторяющиеся паттерны — создавайте классы для типовых объектов.
- 🧩 Компонентный подход — React-компоненты тоже используют ООП под капотом.
🚀 Продолжайте практиковаться! ООП — это не теория, а инструмент. Чем больше пишете, тем лучше понимаете.