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

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

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

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

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

let obj2 = new obj.constructor();

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

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

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

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

let user = new User('John');
let user2 = new user.constructor('Pete');

alert( user2.name ); // Pete (працює!)

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

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

Наприклад:

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

let user = new User('John');
let user2 = new user.constructor('Pete');

alert( user2.name ); // undefined

Чому user2.name є undefined?

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

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

Таким чином, в кінці, ми отримуємо let user2 = new Object('Pete').

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

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