Skip to main content

Кілька конструкторів у класі

Клас у JavaScript може мати рівно один constructor(). Перевантаження за кількістю чи типами аргументів у мові немає, тому «кілька конструкторів» імітують перевіркою аргументів, об'єктом параметрів, статичними фабриками або успадкуванням.

Теорія

TL;DR

  • Два constructor() в одному класі це SyntaxError: A class may only have one constructor.
  • Перевантаження методів, як у Java чи C#, у JavaScript відсутнє в принципі.
  • Найпростіша заміна: один конструктор, який сам розбирає свої аргументи.
  • Для багатьох параметрів зручніший об'єкт параметрів із деструктуризацією та значеннями за замовчуванням.
  • Найчистіший підхід у реальних проєктах: статичні фабричні методи User.fromName(), User.fromObject().
  • Різні набори полів іноді краще виражати різними класами-нащадками.

Швидкий приклад

javascript
class User { constructor(name) { this.name = name; } // SyntaxError: a constructor cannot be declared twice constructor(name, age) { this.name = name; this.age = age; } }

SyntaxError: A class may only have one constructor

Чому кількох конструкторів не буває

У JavaScript функція не має сигнатури: кількість і типи аргументів не є частиною її ідентичності. Виклик new User("Tim") і new User("Alex", 25) потрапляють в одну й ту саму функцію, а зайві аргументи просто стають undefined. Через це рушію нема з чого вибирати потрібний конструктор, і повторне оголошення constructor заборонене на рівні синтаксису, ще до виконання коду.

Отже, гнучкість треба будувати всередині єдиного конструктора або поруч із ним.

Варіант 1: перевірка аргументів усередині одного конструктора

javascript
class User { constructor(name, age) { if (typeof age === "undefined") { this.name = name; this.age = "unknown"; } else { this.name = name; this.age = age; } } } const u1 = new User("Tim"); const u2 = new User("Alex", 25); console.log(u1); // { name: "Tim", age: "unknown" } console.log(u2); // { name: "Alex", age: 25 }

Цей підхід працює як «перевантаження за кількістю аргументів». Він доречний, поки перевірок одна або дві; далі конструктор швидко перетворюється на купу if.

Варіант 2: об'єкт параметрів і значення за замовчуванням

Коли параметрів багато, зручніше приймати об'єкт:

javascript
class User { constructor({ name, age = null, email = null } = {}) { this.name = name; this.age = age; this.email = email; } } const u1 = new User({ name: "Tim" }); const u2 = new User({ name: "Alex", email: "alex@example.com" }); console.log(u2);

Виклик читається зрозуміліше, порядок аргументів перестає мати значення, а = {} дозволяє створити об'єкт узагалі без аргументів.

Для невеликої кількості полів вистачає звичайних значень за замовчуванням:

javascript
class Point { constructor(x = 0, y = 0) { this.x = x; this.y = y; } } const a = new Point(); // (0, 0) const b = new Point(10); // (10, 0) const c = new Point(5, 7); // (5, 7)

Один конструктор, але три легальні способи виклику.

Варіант 3: статичні фабричні методи

Це найпопулярніший підхід у реальних проєктах: замість кількох конструкторів ви робите кілька фабрик з іменами, які пояснюють намір.

javascript
class User { constructor(name, age) { this.name = name; this.age = age; } static fromName(name) { return new User(name, null); } static fromObject(obj) { return new User(obj.name, obj.age); } } const u1 = User.fromName("Tim"); const u2 = User.fromObject({ name: "Alex", age: 30 }); console.log(u1, u2);

Формально це звичайні статичні методи, які повертають екземпляр, але для користувача класу вони виглядають саме як «різні конструктори» і мають промовисті назви на кшталт fromJson чи fromDatabaseRow.

Варіант 4: успадкування

Якщо різні способи створення означають різні набори полів і поведінки, краще виразити це ієрархією класів, де кожен нащадок має власний конструктор:

javascript
class User { constructor(name) { this.name = name; } } class Admin extends User { constructor(name, permissions) { super(name); this.permissions = permissions; } } const u = new User("Tim"); const a = new Admin("Alex", ["edit", "delete"]);

Зведення підходів:

ПідхідЧи допустимоПриклад
Кілька constructor()Ні, синтаксична помилканемає
Один конструктор із перевіркою аргументівТакif (typeof age === "undefined") ...
Об'єкт параметрівТакconstructor({ name, age }) {}
Фабричні методиТакUser.fromName() / User.fromObject()
УспадкуванняТакclass Admin extends User
Опціональні параметриТакconstructor(x = 0, y = 0)

Висновок: конструктор у класі один, але тієї самої гнучкості легко досягти перевірками, фабриками або успадкуванням.

Типові помилки

  • Спроба перенести перевантаження конструкторів із Java чи C#. У JavaScript його немає взагалі, і помилка виникає ще на етапі парсингу.
  • Конструктор, що розрісся до довгого ланцюга if (arguments.length === ...). Це ознака того, що час перейти на фабричні методи.
  • Перевірка if (!age) замість if (typeof age === "undefined"): значення 0 і порожній рядок теж хибні, тож коректні дані випадково підмінюються значенням за замовчуванням.
  • Об'єкт параметрів без = {} у кінці: тоді виклик new User() кине TypeError, бо деструктуризувати undefined неможливо.
  • Фабричний метод, який жорстко пише new User(...) замість new this(...): у нащадку такий метод поверне батьківський тип.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.