назад до уроку

Створення нового об’єкта з одинаковим конструктором

важливість: 5

Уявіть собі, у нас є довільний об’єкт obj, який створений функцією-конструктором – ми не знаємо яким саме конструктором, але потрібно створити новий об’єкт використовуючи той самий конструктор.

Чи можна створити новий об’єкт ось так?

let obj2 = new obj.constructor();

Покажіть приклад функції-конструктора для обєкта obj, який забезпечить правильну роботу такого коду, а також приклад, який, при такому коді, працює неправильно.

Так, ми можемо використовувати такий підхід якщо ми впевнені, що властивість "constructor" має правильне значення.

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

function User(name) {
  this.name = name;
}

let user = new User('Богдан');
let user2 = new user.constructor('Данило');

alert( user2.name ); // Данило (працює!)

Код працює, тому що User.prototype.constructor == User.

…Але якщо хтось, якщо можна так виразитись, перезапише User.prototype і забуде додати властивість constructor в посиланні властивості об’єкта User, тоді цей код не буде працювати правильно.

Наприклад:

function User(name) {
  this.name = name;
}
User.prototype = {}; // (*)

let user = new User('Богдан');
let user2 = new user.constructor('Данило');

alert( user2.name ); // undefined

Чому user2.name є undefined?

Ось тут пояснення як new user.constructor('Данило') працює:

  1. Спочатку, здійснюється пошук у властивості constructor об’єкта user. Нічого не знаходять.
  2. Потім переключаються на ланцюжок прототипу. Прототипом для об’єкта user є User.prototype, і він також не має властивості constructor (тому що ми “забули” призначити його правильним чином!).
  3. Йдучи далі по ланцюжку прототипу, визначаємо, що User.prototype є простий об’єкт, його прототипом є вбудований глобальний Object.prototype.
  4. Врешті, для вбудованого Object.prototype, є вбудований конструктор глобального об’єкта Object.prototype.constructor == Object от він і використовується.

Таким чином, в кінці кінців, ми отримуємо те ж саме, якби написали let user2 = new Object('Данило').

Ймовірно, це не те, що нам потрібно. Ми би хотіли стоврити new User, а не new Object. Це і є наслідки пропуску властивості constructor.

(на випадок, якщо вас зацікавить, виклик new Object(...) перетворює його аргументи на об’єкт. Це в теорії, але на практиці ніхто не викликає new Object з аргументами; і загалом, new Object майже не використовують для створення нових об’єктів).