Apakah Pola "OLOO (Objects Linking to Other Objects)" Kyle Simpson berbeda dengan pola desain Prototipe? Selain menciptakannya dengan sesuatu yang secara khusus menunjukkan "menghubungkan" (perilaku prototipe) dan menjelaskan bahwa tidak ada "penyalinan" yang terjadi di sini (perilaku kelas), apa sebenarnya yang diperkenalkan oleh polanya?
Berikut ini contoh pola Kyle dari bukunya, "You Don't Know JS: this & Object Prototypes":
var Foo = {
init: function(who) {
this.me = who;
},
identify: function() {
return "I am " + this.me;
}
};
var Bar = Object.create(Foo);
Bar.speak = function() {
alert("Hello, " + this.identify() + ".");
};
var b1 = Object.create(Bar);
b1.init("b1");
var b2 = Object.create(Bar);
b2.init("b2");
b1.speak(); // alerts: "Hello, I am b1."
b2.speak(); // alerts: "Hello, I am b2."
javascript
design-patterns
shmuli
sumber
sumber
Jawaban:
OLOO merangkul rantai prototipe apa adanya, tanpa perlu melapisi semantik lain (IMO membingungkan) untuk mendapatkan tautan.
Jadi, kedua cuplikan ini memiliki hasil yang SAMA PERSIS, tetapi sampai di sana secara berbeda.
Bentuk Pembuat:
Formulir OLOO:
Di kedua cuplikan, sebuah
x
objek[[Prototype]]
ditautkan ke objek (Bar.prototype
atauBarObj
), yang pada gilirannya ditautkan ke objek ketiga (Foo.prototype
atauFooObj
).Hubungan dan delegasi identik di antara cuplikan. Penggunaan memori identik di antara cuplikan. Kemampuan untuk menciptakan banyak "anak" (alias, banyak benda seperti
x1
melaluix1000
, dll) identik antara potongan. Kinerja delegasi (x.y
danx.z
) identik di antara cuplikan. Kinerja pembuatan obyek adalah lebih lambat dengan OLOO, tapi kewarasan memeriksa bahwa mengungkapkan bahwa kinerja lambat adalah benar-benar tidak masalah.Menurut saya, yang ditawarkan OLOO adalah jauh lebih mudah untuk hanya mengekspresikan objek dan menghubungkannya secara langsung, daripada menghubungkannya secara tidak langsung melalui konstruktor /
new
mekanisme. Yang terakhir berpura-pura tentang kelas tetapi sebenarnya hanya sintaks yang buruk untuk mengekspresikan delegasi ( catatan samping: begitu jugaclass
sintaks ES6 !).OLOO baru saja menghentikan perantara.
Berikut perbandingan lain dari
class
vs OLOO.sumber
Object.create(...)
berkali-kali lebih lambat darinew
. jsperf.com/object-create-vs-crockford-vs-jorge-vs-constructor/…Saya membaca buku Kyle, dan menurut saya itu sangat informatif, terutama detail tentang bagaimana
this
terikat.Kelebihan:
Bagi saya, ada beberapa kelebihan OLOO:
1. Kesederhanaan
OLOO mengandalkan
Object.create()
untuk membuat objek baru yang[[prototype]]
-link ke objek lain. Anda tidak perlu memahami bahwa fungsi memiliki aprototype
properti atau khawatir tentang potensi jebakan terkait yang berasal dari modifikasinya.2. Sintaks yang lebih bersih
Ini bisa diperdebatkan, tetapi saya merasa sintaks OLOO (dalam banyak kasus) lebih rapi dan lebih ringkas daripada pendekatan javascript 'standar', terutama dalam hal polimorfisme (
super
panggilan -style).Kekurangan:
Saya pikir ada satu desain yang dipertanyakan (yang sebenarnya berkontribusi pada poin 2 di atas), dan itu berkaitan dengan shadowing:
Ide di balik ini adalah bahwa objek memiliki fungsi yang lebih spesifik yang kemudian didelegasikan secara internal ke fungsi di bagian bawah rantai. Misalnya, Anda mungkin memiliki
resource
objek dengansave()
fungsi di atasnya yang mengirimkan versi JSON dari objek ke server, tetapi Anda mungkin juga memilikiclientResource
objek yang memilikistripAndSave()
fungsi, yang terlebih dahulu menghapus properti yang tidak boleh dikirim ke server. .Masalah potensial adalah: jika orang lain datang dan memutuskan untuk membuat
specialResource
objek, tidak sepenuhnya menyadari keseluruhan rantai prototipe, mereka mungkin secara wajar * memutuskan untuk menyimpan stempel waktu untuk penyimpanan terakhir di bawah properti bernamasave
, yang membayangisave()
fungsionalitas dasar pada yangresource
objek dua link ke bawah rantai prototipe:Ini adalah contoh yang dibuat-buat, tetapi intinya adalah tidak membayangi properti lain dapat menyebabkan beberapa situasi yang canggung dan penggunaan tesaurus yang berat!
Mungkin ilustrasi yang lebih baik dari ini adalah
init
metode - terutama pedih karena OOLO menghindari fungsi jenis konstruktor. Karena setiap objek terkait kemungkinan besar membutuhkan fungsi seperti itu, mungkin latihan yang membosankan untuk menamainya dengan tepat, dan keunikan mungkin membuat sulit untuk mengingat mana yang akan digunakan.* Sebenarnya itu tidak terlalu masuk akal (
lastSaved
akan jauh lebih baik, tapi ini hanya sebuah contoh.)sumber
[[Prototype]]
sistem itu sendiri, bukan secara spesifik OLOO.b.timeStampedSave();
sebagai penggantia.timeStampedSave();
pada baris terakhir dari potongan kode.Diskusi dalam "You Don't Know JS: this & Object Prototypes" dan presentasi OLOO sangat menggugah pikiran dan saya telah belajar banyak melalui buku ini. Keunggulan pola OLOO dijelaskan dengan baik di jawaban lain; Namun, saya memiliki keluhan hewan peliharaan berikut dengannya (atau saya kehilangan sesuatu yang mencegah saya menerapkannya secara efektif):
1
Ketika "class" "mewarisi" class "lain" dalam pola klasik, kedua fungsi tersebut dapat dinyatakan dengan sintaks yang serupa ( "deklarasi fungsi" atau "pernyataan fungsi" ):
Sebaliknya, dalam pola OLOO, bentuk sintaksis yang berbeda digunakan untuk menentukan basis dan objek turunan:
Seperti yang Anda lihat pada contoh di atas, objek dasar dapat didefinisikan menggunakan notasi literal objek, sedangkan notasi yang sama tidak dapat digunakan untuk objek turunan. Asimetri ini mengganggu saya.
2
Dalam pola OLOO, membuat objek dalam dua langkah:
Object.create
panggil beberapa metode kustom, non standar untuk menginisialisasi objek (yang harus Anda ingat karena ini mungkin berbeda dari satu objek ke objek berikutnya):
Sebaliknya, dalam pola Prototipe Anda menggunakan operator standar
new
:3
Dalam pola klasik, saya dapat membuat fungsi utilitas "statis" yang tidak berlaku langsung ke "instan" dengan menetapkannya langsung ke fungsi "kelas" (sebagai lawannya
.prototype
). Misal seperti fungsisquare
pada kode di bawah ini:Sebaliknya, dalam pola OLOO semua fungsi "statis" tersedia (melalui rantai [[prototipe]]) pada instance objek juga:
sumber
Seperti yang dijelaskan Kyle saat dua objek
[[Prototype]]
dihubungkan, keduanya tidak benar-benar bergantung satu sama lain; sebaliknya mereka adalah objek individu. Anda menautkan satu objek ke objek lainnya dengan[[Prototype]]
tautan yang dapat Anda ubah kapan saja Anda mau. Jika Anda menganggap dua[[Prototype]]
objek tertaut yang dibuat melalui gaya OLOO saling bergantung, Anda juga harus berpikiran sama tentang objek yang dibuat melaluiconstructor
panggilan.Sekarang pikirkan sejenak apakah Anda memikirkan
foo
bar
danbaz
bergantung satu sama lain?Sekarang mari lakukan hal yang sama
constructor
dengan kode gaya ini-Satu-satunya perbedaan b / w yang terakhir dan mantan kode adalah bahwa dalam satu terakhir
foo
,bar
,baz
bbjects dihubungkan satu sama-lain melalui objek sewenang-wenang dari merekaconstructor
fungsi (Foo.prototype
,Bar.prototype
,Baz.prototype
) tapi di bekas satu (OLOO
gaya) mereka terkait langsung. Kedua cara Anda hanya menghubungkanfoo
,bar
,baz
satu sama lain, langsung di bekas satu dan tidak langsung dalam satu terakhir. Namun, dalam kedua kasus, objek tidak bergantung satu sama lain karena tidak benar-benar seperti instance dari kelas mana pun yang pernah dibuat instance-nya, tidak dapat dibuat untuk mewarisi dari kelas lain. Anda selalu dapat mengubah objek mana yang harus didelegasikan oleh objek juga.Jadi mereka semua tidak bergantung satu sama lain.
Ya itu memang mungkin-
Mari kita gunakan
Tech
sebagai objek utilitas-buat objek sebanyak yang Anda ingin ditautkan
Tech
-Apakah Anda berpikir
html
,css
,js
objek yang terhubung satu sama-lain? Tidak, mereka tidak. Sekarang mari kita lihat bagaimana kita bisa melakukannya denganconstructor
fungsi-buat objek sebanyak yang Anda ingin ditautkan
Tech.proptotype
-Beberapa pemeriksaan (menghindari console.log) -
Bagaimana Anda pikir ini
constructor
Objects -gaya (html
,css
,js
) Objek berbeda dariOLOO
kode-gaya? Sebenarnya mereka melayani tujuan yang sama. Dalam-OLOO
gaya satu objek didelegasikan keTech
(delegasi ditetapkan secara eksplisit) sedangkan dalamconstructor
gaya satu objek didelegasikan keTech.prototype
(delegasi ditetapkan secara implisit). Pada akhirnya Anda akan menghubungkan ketiga objek, yang tidak memiliki keterkaitan satu sama lain, ke satu objek, secara langsung menggunakanOLOO
-style, secara tidak langsung menggunakanconstructor
-style.Tidak, di
ObjB
sini tidak seperti instance (dalam bahasa berbasis klasik) dari kelas mana punObjA
. Ini bisa dikatakan sepertiobjB
objek dibuat delegasi keObjA
objek pada waktu pembuatannya " . Jika Anda menggunakan konstruktor, Anda akan melakukan 'penggandengan' yang sama, meskipun secara tidak langsung dengan menggunakan.prototype
s.sumber
@Jamur_kejang
Mungkin kita bisa melakukan sesuatu seperti ini.
Tentu saja, membuat objek Point3D yang ditautkan ke prototipe objek Point2D agak konyol, tapi itu tidak penting (saya ingin konsisten dengan contoh Anda). Ngomong-ngomong, sejauh keluhannya:
Asimetri dapat diperbaiki dengan ES6's Object.setPrototypeOf atau lebih disukai
__proto__ = ...
yang saya gunakan. Sekarang kita juga bisa menggunakan super pada objek biasa, seperti yang terlihat diPoint3D.init()
. Cara lain adalah melakukan sesuatu sepertimeskipun saya tidak terlalu suka sintaksnya.
Kami selalu dapat membungkus
p = Object.create(Point)
dan kemudianp.init()
menjadi konstruktor. misPoint.create(x,y)
. Menggunakan kode di atas kita dapat membuatPoint3D
"instance" dengan cara berikut.Saya baru saja membuat peretasan ini untuk meniru metode statis di OLOO. Saya tidak yakin apakah saya suka atau tidak. Ini membutuhkan pemanggilan properti khusus di atas setiap metode "statis". Misalnya, saya telah membuat
Point.create()
metode menjadi statis.Alternatifnya, dengan Simbol ES6 Anda dapat memperluas kelas dasar Javascript dengan aman. Jadi Anda bisa menyimpan sendiri beberapa kode dan mendefinisikan properti khusus di Object.prototype. Sebagai contoh,
sumber
@james emanon - Jadi, yang Anda maksud adalah warisan berganda (dibahas di halaman 75 dalam buku "You Don't Know JS: this & Object Prototypes"). Dan mekanisme itu bisa kita temukan di fungsi "perluasan" garis bawah misalnya. Nama objek yang Anda sebutkan dalam contoh Anda sedikit mencampurkan apel, jeruk, dan permen, tetapi saya mengerti maksudnya. Dari pengalaman saya, ini adalah versi OOLO:
Ini adalah contoh sederhana tetapi poin yang ditunjukkan adalah bahwa kita hanya merangkai objek bersama dalam struktur / formasi yang agak datar dan masih memiliki kemungkinan untuk menggunakan metode dan properti dari beberapa objek. Kami mencapai hal yang sama seperti dengan pendekatan kelas / "menyalin properti". Disimpulkan oleh Kyle (halaman 114, "this & Object Prototypes"):
Saya memahami bahwa cara yang lebih alami bagi Anda adalah dengan menyatakan semua objek "induk" (hati-hati :)) di satu tempat / fungsi memanggil pemodelan keseluruhan rantai.
Yang dibutuhkan adalah pergeseran dalam pemikiran dan pemodelan masalah dalam aplikasi kita yang sesuai dengan itu. Saya juga mulai terbiasa. Semoga membantu dan keputusan akhir dari Kyle sendiri akan bagus. :)
sumber
@Marcus, sama seperti Anda, saya tertarik dengan OLOO dan juga tidak menyukai asimetri seperti yang dijelaskan pada poin pertama Anda. Saya telah bermain dengan abstraksi untuk mengembalikan simetri. Anda bisa membuat
link()
fungsi yang digunakan sebagai penggantiObject.create()
. Saat digunakan, kode Anda akan terlihat seperti ini ...Ingatlah bahwa
Object.create()
memiliki parameter kedua yang dapat dilewatkan. Berikut adalah fungsi link yang memanfaatkan parameter kedua. Ini juga memungkinkan sedikit konfigurasi khusus ...Tentu saja, saya pikir @Kaos tidak akan mendukung
init()
fungsi di objek Point3D. ;-)sumber
Object.assign()
denganObject.create()
, kita dapat sangat menyederhanakanlink()
fungsi di atas. Sebagai gantinya, kita bisa menggunakan ini:function create(delegate, props) { return Object.assign(Object.create(delegate), props); }
. Atau lebih baik lagi, kita dapat menggunakan Menggarisbawahi atau Lodash untuk membuatnya benar-benar ringkas:_.create(delegate, props)
.Apakah ada cara untuk OLOO lebih dari "dua" objek .. semua contoh saya terdiri dari contoh berbasis (lihat contoh OP). Katakanlah kita memiliki objek berikut, bagaimana kita bisa membuat objek "keempat" yang memiliki atribut dari tiga 'lainnya'? ala ...
objek-objek ini sewenang-wenang, dan dapat mencakup semua jenis perilaku. Tetapi intinya adalah, kita memiliki sejumlah 'n' objek, dan objek baru kita membutuhkan sesuatu dari ketiganya.
Alih-alih contoh yang diberikan ala:
TAPI, newObject = (Button, Bike, Shoe) ......
Bagaimana pola untuk menjalankan ini di OLOO?
sumber
Object.assign()
- developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… . Jika menulis di ES5, Anda dapat menggunakan Underscore_.extend()
atau Lodash_.assign()
. Berikut video yang bagus untuk menjelaskan ... youtu.be/wfMtDGfHWpA . Jika Anda memiliki properti yang bertabrakan, yang terakhir menang - jadi keteraturan itu penting.