Skip to main content

return усередині конструктора

return у конструкторі потрібен лише для того, щоб підмінити створюваний екземпляр іншим об'єктом. Без нього конструктор неявно повертає this, а повернений примітив рушій просто ігнорує.

Теорія

TL;DR

  • return у конструкторі не обов'язковий: за замовчуванням повертається this.
  • Якщо повернути об'єкт, він замінює this і саме він стає результатом new.
  • Якщо повернути примітив, його ігноровано, результатом усе одно буде this.
  • У класі-нащадку super() треба викликати до будь-якого return, інакше ReferenceError.
  • Цю поведінку використовують шаблони Singleton, Factory та Proxy.

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

javascript
class User { constructor(name) { this.name = name; } } const u = new User("Tim"); console.log(u); // User { name: "Tim" }

Звичайна поведінка конструктора

Коли ви пишете new User("Tim"), рушій робить приблизно таке:

  1. Створює новий порожній об'єкт {}.
  2. Встановлює прототипом цього об'єкта User.prototype.
  3. Викликає constructor, де this посилається на цей новий об'єкт.
  4. Повертає this з конструктора за замовчуванням.

Тобто якщо ви нічого не повертаєте, return this виконується неявно.

Повернення об'єкта підміняє this

Якщо return віддає об'єкт, він замінює створений екземпляр:

javascript
class User { constructor(name) { this.name = name; return { custom: "another object" }; } } const u = new User("Tim"); console.log(u); // { custom: "another object" }

Зверніть увагу: this.name = name усе одно виконалося, просто той об'єкт нікуди не потрапив. Повернений об'єкт не має ані User.prototype, ані методів класу, тож u instanceof User буде false.

Повернення примітива ігнорується

Числа, рядки, булеві значення та інші примітиви не можуть перезаписати this:

javascript
class User { constructor(name) { this.name = name; return 42; } } const u = new User("Tim"); console.log(u); // User { name: "Tim" }

Помилки не буде, значення просто відкидається. Це стосується і null: він примітив, тому теж ігнорується, а от return undefined нічого не змінює за визначенням.

Навіщо це потрібно: Singleton і фабрики

Можливість повернути свій об'єкт існує саме для того, щоб конструктор міг віддати щось особливе. Класичний приклад, Singleton, тобто один спільний екземпляр на всі виклики:

javascript
class Database { constructor() { if (Database.instance) { return Database.instance; // always hands back the same object } this.connected = true; Database.instance = this; } } const a = new Database(); const b = new Database(); console.log(a === b); // true

Тут return this не потрібен, бо рушій робить це сам, а return Database.instance підміняє новий екземпляр наявним.

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

javascript
class Example { constructor(x) { this.x = x; if (x > 10) return { value: "too large" }; } } console.log(new Example(5)); // Example { x: 5 } console.log(new Example(20)); // { value: "too large" }

return у класах-нащадках

У класі без extends і в класі з extends правило те саме: повернений об'єкт замінює this.

javascript
class A {} class B extends A { constructor() { super(); return { name: "replacement" }; } } const b = new B(); console.log(b); // { name: "replacement" }

Але super() лишається обов'язковим навіть тоді, коли ви повертаєте власний об'єкт:

javascript
class A {} class B extends A { constructor() { // error, even though there is a return return { test: 1 }; } } new B(); // ReferenceError: Must call super constructor before returning from derived constructor

Правила в одному місці:

СценарійЩо повертається
Немає returnthis, тобто створений екземпляр
return thisтой самий екземпляр
return { ... }цей об'єкт замість this
return 42 / "hi" / trueігнорується, повертається this
Нащадок без super()помилка: super() має бути до return

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

  • Повернення об'єктного літерала «для зручності» і подальше здивування, що instanceof та методи класу зникли: підмінений об'єкт не має прототипу класу.
  • Очікування, що return 42 зробить new User() числом. Примітиви з конструктора ігноруються без жодного попередження.
  • Ранній return у конструкторі-нащадку до super(). Це ReferenceError, а не тихий вихід.
  • Singleton через return Database.instance разом із важкою ініціалізацією до цієї перевірки: робота виконується зайвий раз, хоча результат викидається.
  • Плутанина з null: це примітив, тому new віддасть this, а не null.

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

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

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