Чому використання конструкторів не рекомендується створювати прототипи?


10

Швидкий фон: У JavaScript функція конструктора для кожного типу об'єкта має prototypeвластивість. prototypeВідноситься до об'єкта , який кожен збудований об'єкт використовує в якості наступного кроку вгору в своїй ланцюга прототипів. Коли ви хочете, щоб один тип був притаманний іншому типу, ви можете встановити prototypeдочірній тип на новий екземпляр батьківського типу.

Наприклад:

var Parent = function() { /* constructor business */ }
Parent.prototype.parentProp = "some parent property";

var Child = function() { /* constructor business */ }
Child.prototype = /*** !! Some prototype object goes here !! ***/

У моєму запитанні задається питання про те, який код повинен знаходитись у " Some prototype object goes here" місці у вказаному вище коді. Перший мій інстинкт - побудувати екземпляр батьківського (тобто new Parent()), але в коментарі до відповіді на те, чи це безпечний спосіб копіювання одного прототипу об'єктів до іншого? , один користувач пише:

Ні, не використовуйте new bar()для прототипу об'єкт!

(... яку думку я бачив у багатьох відповідях та коментарях, але це єдиний приклад, який я маю на даний момент.)

Інший варіант - використовувати Object.create(Parent.prototype)як Child.prototype. Наскільки мені відомо, це також створює новий Parentекземпляр, але він не запускає Parentконструктор.

Чи може хтось пояснити, чому слід уникати запуску функції конструктора під час генерації прототипу об'єкта з батьківського типу? Чи існує якась значна технічна проблема, яка виникає (можливо, з кількома рівнями спадкування)? Або така закономірність - це неправильне використання конструкторів, що стикається з якоюсь найкращою прототиповою практикою (наприклад, запуск конструктора при створенні прототипу порушує деяке розділення проблем)?

Відповіді:


5

Тому що це функція, яку не потрібно викликати. newне так відрізняється від звичайного виклику функції в JavaScript.

Конструктор може зробити більше, ніж просто встановити поля. Наприклад, якщо він перевіряє вхідні дані, ви викликаєте помилку перевірки, коли ви просто намагалися встановити ланцюжок спадкування.

І вам не потрібно Object.create, цього достатньо:

function objectCreate( proto ) {
    function T(){}
    T.prototype = proto;
    return new T();
}

Але саме так Object.createреалізовано.
Кейсі Чу

@CaseyChu зовсім не є. І я згадував це, тому що у зв’язаному дописі хтось сказав " Object.createне працює в IE8" - це просто марний коментар, коли ви можете впровадити його для цього випадку використання за 2 секунди в будь-якому браузері.
Есаїлія

2

Тепер, коли моє розуміння трохи розширилося, я хотів би спиратися на відповідь Ісаїлії на конкретному прикладі:

Одне особливе занепокоєння полягає в тому, що конструктор може встановлювати властивості, характерні для конкретних примірників. Таким чином, якщо ви використовуєте об'єкт-прототип, створений за допомогою new, всі ваші дочірні екземпляри можуть мати спільне певне, визначене конструктором властивість прототипу.

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

var Parent = function() { this.id = Math.random(); }
Parent.prototype.parentProp = "some parent property";

var Child = function() { /* constructor business */ }
Child.prototype = new Parent();

Це призведе до того, що всі Child екземпляри поділять одне idвластивість прототипу, успадковане від одного і єдиного new Parent()об'єкта, що використовується як Child.prototype.

Кращим підходом для цього випадку є використання Object.createта безпосередній виклик материнського конструктора (якщо потрібно) всередині дочірнього конструктора:

var Parent = function() { this.id = Math.random(); }
Parent.prototype.parentProp = "some parent property";

var Child = function() {
    // run `this` through the Parent constructor function
    Parent.apply(this, arguments);
}
Child.prototype = Object.create(Parent.prototype);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.