Mengapa penggunaan konstruktor tidak disarankan saat membuat prototipe?

10

Latar belakang cepat: Dalam JavaScript, fungsi konstruktor untuk setiap jenis objek memiliki prototypeproperti. The prototypemengacu pada sebuah objek yang masing-masing dibangun menggunakan objek sebagai langkah berikutnya dalam rantai prototipe. Saat Anda ingin satu tipe melekat dari tipe lain, Anda bisa mengatur prototypetipe anak ke instance baru dari tipe induk.

Sebagai contoh:

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

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

Pertanyaan saya bertanya tentang kode apa yang harus ada di tempat " Some prototype object goes here" di kode di atas. Naluri pertama saya adalah membuat turunan dari induknya (yaitu, new Parent()), tetapi dalam komentar untuk jawaban pada Apakah ini cara yang aman untuk menyalin satu objek prototipe ke yang lain? , satu pengguna menulis:

Tidak, jangan gunakan new bar()untuk objek prototipe!

(... yang merupakan pendapat yang telah saya lihat di banyak jawaban dan komentar SO, tetapi ini adalah satu-satunya contoh yang saya miliki saat ini.)

Opsi lainnya adalah menggunakan Object.create(Parent.prototype)sebagai Child.prototype. Sejauh yang saya tahu, ini juga menciptakan Parentcontoh baru , tetapi tidak menjalankan Parentkonstruktor.

Adakah yang bisa menjelaskan mengapa menjalankan fungsi konstruktor harus dihindari ketika membuat objek prototipe dari tipe induk? Apakah ada beberapa masalah teknis signifikan yang muncul (mungkin dengan berbagai tingkat warisan)? Atau apakah pola seperti itu merupakan penyalahgunaan konstruktor yang bertentangan dengan beberapa praktik terbaik prototipikal (misalnya, menjalankan konstruktor saat membuat prototipe melanggar beberapa pemisahan perhatian)?

apsillers
sumber

Jawaban:

5

Karena itu adalah fungsi yang tidak perlu dipanggil. newtidak jauh berbeda dari pemanggilan fungsi biasa dalam Javascript.

Konstruktor dapat melakukan lebih dari sekadar mengatur bidang. Misalnya, jika itu memvalidasi data yang masuk, maka Anda akan menyebabkan kesalahan validasi ketika Anda hanya mencoba untuk mengatur rantai pewarisan.

Dan Anda tidak perlu Object.create, ini sudah cukup:

function objectCreate( proto ) {
    function T(){}
    T.prototype = proto;
    return new T();
}
Esailija
sumber
Tapi itulah cara Object.createditerapkannya.
Casey Chu
@CaseyChu sama sekali tidak. Dan saya menyebutkannya karena dalam posting yang terhubung seseorang berkata " Object.createtidak berfungsi di IE8" - yang merupakan komentar tidak berguna ketika Anda dapat mengimplementasikannya untuk use case ini dalam 2 detik pada browser apa pun.
Esailija
2

Sekarang setelah pemahaman saya sedikit melebar, saya ingin membangun jawaban Esailija dengan contoh spesifik:

Satu perhatian khusus adalah bahwa konstruktor dapat mengatur properti spesifik-instance. Dengan demikian, jika Anda menggunakan objek prototipe yang dibuat dengan new, semua instance anak Anda dapat berbagi properti instans-spesifik tunggal yang ditentukan konstruktor dari prototipe.

Misalnya, Parentsetiap instance memiliki idproperti unik yang ditetapkan sebagai waktu konstruksi:

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

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

Ini akan menyebabkan semua Child instance membagikan idproperti prototipe tunggal yang diwarisi dari objek satu-satunya yang new Parent()digunakan Child.prototype.

Pendekatan yang lebih baik untuk kasus ini adalah dengan menggunakan Object.createdan langsung memanggil konstruktor induk (jika perlu) di dalam konstruktor anak:

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);
apsillers
sumber