Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Класи в JavaScript». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Клас це синтаксичний цукор над функцією-конструктором і прототипами: `class` описує тип об'єкта декларативно, але модель успадкування лишається прототипною.** Тіло класу задає `constructor`, який виконується на `new`, і методи, які потрапляють у `prototype` і тому спільні для всіх екземплярів. Зверху додаються `extends` і `super()` для успадкування, `static` для членів самого класу, приватні поля з `#` та аксесори `get` / `set`. ```javascript class User { constructor(name) { this.name = name; } sayHi() { console.log(`Привіт, мене звати ${this.name}`); } } new User('Alex').sayHi(); // Привіт, мене звати Alex ``` **Ключове:** клас це зручний синтаксис над прототипами, а не нова модель успадкування.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**Клас у JavaScript це синтаксичний цукор над функцією-конструктором і прототипами.** Ззовні це декларативний опис типу об'єкта, а під капотом усе працює так само, як і раніше: методи лягають у `prototype`, а `new` створює новий об'єкт і прив'язує до нього `this`. Виглядає й читається такий код значно простіше. ## Теорія ### TL;DR - `class` це синтаксичний цукор над функцією-конструктором і прототипами, а не нова модель успадкування. - `constructor()` викликається при `new`, а методи з тіла класу потрапляють у `prototype` і є спільними для всіх екземплярів. - `extends` зв'язує прототипи двох класів, `super()` викликає конструктор батька. - `static` робить метод або властивість членом самого класу, а не екземпляра. - Поля з `#` приватні й доступні лише всередині тіла класу (ES2022), а `get` / `set` керують читанням і записом властивостей. - Класи не піднімаються (немає hoisting) як функції, а їхні методи не перелічувані (non-enumerable). ### Швидкий приклад ```javascript class User { constructor(name, age) { this.name = name; this.age = age; } sayHi() { console.log(`Привіт, мене звати ${this.name}`); } } const user1 = new User('Alex', 25); user1.sayHi(); // Привіт, мене звати Alex ``` - `class` оголошує клас. - `constructor()` це спеціальний метод, який викликається при `new User()`. - `this` це посилання на об'єкт, що створюється. - Методи класу автоматично потрапляють у `prototype`. ### Як це виглядає під капотом Цей код: ```javascript class User { constructor(name) { this.name = name; } sayHi() { console.log(this.name); } } ``` еквівалентний старому ES5-коду: ```javascript function User(name) { this.name = name; } User.prototype.sayHi = function() { console.log(this.name); }; ``` Різниця не в моделі, а в деталях поведінки: тіло класу завжди виконується у strict mode, методи класу не перелічувані, тому `for...in` по екземпляру їх не побачить, а викликати клас без `new` взагалі не можна. ### Складові класу | Можливість | Опис | | --- | --- | | **constructor()** | Метод, який виконується при створенні об'єкта (`new`) | | **методи класу** | Додаються в `prototype` і доступні всім екземплярам | | **extends** | Успадкування від іншого класу | | **super()** | Виклик конструктора батька | | **static** | Статичні методи та властивості, належать самому класу | | **приватні поля** (`#`) | Поля, недоступні поза класом | | **геттери та сеттери** | Дозволяють керувати читанням і записом властивостей | Клас можна оголосити не лише інструкцією, а й виразом (class expression): ```javascript const User = class { sayHi() { console.log('Hi!'); } }; new User().sayHi(); // Hi! ``` Або дати йому ім'я, видиме тільки всередині самого визначення: ```javascript const User = class MyUser { getClassName() { return MyUser.name; } }; ``` ### Успадкування: extends і super ```javascript class Animal { constructor(name) { this.name = name; } speak() { console.log(`${this.name} видає звук.`); } } class Dog extends Animal { constructor(name, breed) { super(name); // викликає constructor батька this.breed = breed; } speak() { console.log(`${this.name} гавкає!`); } } const rex = new Dog('Rex', 'вівчарка'); rex.speak(); // Rex гавкає! ``` - `extends` зв'язує прототипи класів. - `super()` викликає `constructor` батька, і в похідному класі його треба викликати до першого звернення до `this`. - Методи можна перевизначати, як у класичному ООП. ### static, приватні поля та аксесори Статичні методи й властивості належать **самому класу**, а не його екземплярам: ```javascript class MathUtil { static add(a, b) { return a + b; } } console.log(MathUtil.add(2, 3)); // 5 ``` Приватні поля та методи (`#`) додані в ES2022: ```javascript class Account { #balance = 0; // приватне поле deposit(amount) { this.#balance += amount; } getBalance() { return this.#balance; } } const acc = new Account(); acc.deposit(100); console.log(acc.getBalance()); // 100 console.log(acc.#balance); // помилка: приватна властивість ``` Поля з `#` доступні **лише всередині класу**. Геттери й сеттери дозволяють керувати тим, як властивість читається і змінюється: ```javascript class User { constructor(name) { this._name = name; } get name() { return this._name.toUpperCase(); } set name(value) { this._name = value.trim(); } } const user = new User(' tim '); console.log(user.name); // TIM user.name = ' Alex '; console.log(user.name); // ALEX ``` ### Клас проти функції-конструктора | Критерій | Функція-конструктор | Клас | | --- | --- | --- | | Синтаксис | Старий, громіздкий | Сучасний, декларативний | | `new` обов'язковий | Так | Так | | Методи | Через `prototype` | Усередині тіла класу | | Поведінка `this` | Може бути непередбачуваною | Зрозуміла, стандартна | | Підтримка `extends` | Вручну | Вбудована | | Приватні поля | Немає | Є (через `#`) | Коротке резюме синтаксису: | Поняття | Що робить | | --- | --- | | `class` | Оголошує клас | | `constructor` | Метод, що викликається при `new` | | `extends` | Успадкування | | `super()` | Виклик батьківського конструктора | | `static` | Методи класу, а не екземпляра | | `#field` | Приватна властивість | | `get` / `set` | Керування доступом до властивостей | ### Типові помилки 1. **Думати, що класи піднімаються, як функції.** Оголошення класу потрапляє в temporal dead zone, тому звернення до нього вище за рядок з `class` падає: ```javascript const user = new User(); // ReferenceError class User {} ``` 2. **Викликати клас без `new`.** `User('Alex')` дає `TypeError: Class constructor User cannot be invoked without 'new'`, тоді як стара функція-конструктор у такому виклику мовчки псувала глобальний об'єкт. 3. **Звертатися до `this` до виклику `super()`.** У похідному класі `this` ще не існує, доки не відпрацював конструктор батька, тому буде `ReferenceError`. 4. **Чекати на методи класу у `for...in`.** Вони не перелічувані, на відміну від властивостей, дописаних у прототип вручну. 5. **Передавати метод як колбек і втрачати `this`.** `setTimeout(user.sayHi, 0)` викличе метод без прив'язки; потрібні `user.sayHi.bind(user)`, стрілкова обгортка або поле класу зі стрілковою функцією. 6. **Плутати `#balance` з угодою про іменування `_balance`.** Підкреслення це лише домовленість, а поле з `#` справді недоступне ззовні: звернення до нього поза тілом класу є синтаксичною помилкою.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.