return усередині конструктора
return у конструкторі потрібен лише для того, щоб підмінити створюваний екземпляр іншим об'єктом. Без нього конструктор неявно повертає this, а повернений примітив рушій просто ігнорує.
Теорія
TL;DR
returnу конструкторі не обов'язковий: за замовчуванням повертаєтьсяthis.- Якщо повернути об'єкт, він замінює
thisі саме він стає результатомnew. - Якщо повернути примітив, його ігноровано, результатом усе одно буде
this. - У класі-нащадку
super()треба викликати до будь-якогоreturn, інакшеReferenceError. - Цю поведінку використовують шаблони Singleton, Factory та Proxy.
Швидкий приклад
class User {
constructor(name) {
this.name = name;
}
}
const u = new User("Tim");
console.log(u); // User { name: "Tim" }Звичайна поведінка конструктора
Коли ви пишете new User("Tim"), рушій робить приблизно таке:
- Створює новий порожній об'єкт
{}. - Встановлює прототипом цього об'єкта
User.prototype. - Викликає
constructor, деthisпосилається на цей новий об'єкт. - Повертає
thisз конструктора за замовчуванням.
Тобто якщо ви нічого не повертаєте, return this виконується неявно.
Повернення об'єкта підміняє this
Якщо return віддає об'єкт, він замінює створений екземпляр:
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:
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, тобто один спільний екземпляр на всі виклики:
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 підміняє новий екземпляр наявним.
Так само працює конструктор, який залежно від вхідних даних віддає різні об'єкти:
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.
class A {}
class B extends A {
constructor() {
super();
return { name: "replacement" };
}
}
const b = new B();
console.log(b); // { name: "replacement" }Але super() лишається обов'язковим навіть тоді, коли ви повертаєте власний об'єкт:
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Правила в одному місці:
| Сценарій | Що повертається |
|---|---|
Немає return | this, тобто створений екземпляр |
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.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.