pewarisan berbasis vs berbasis kelas

208

Dalam JavaScript, setiap objek pada saat yang sama adalah instance dan kelas. Untuk melakukan pewarisan, Anda dapat menggunakan instance objek apa pun sebagai prototipe.

Dalam Python, C ++, dll. Ada kelas, dan contoh, sebagai konsep yang terpisah. Untuk melakukan pewarisan, Anda harus menggunakan kelas dasar untuk membuat kelas baru, yang kemudian dapat digunakan untuk menghasilkan turunan turunan.

Mengapa JavaScript mengarah ke arah ini (orientasi objek berbasis prototipe)? apa keuntungan (dan kerugian) dari OO berbasis prototipe sehubungan dengan OO tradisional, berbasis kelas?

Stefano Borini
sumber
10
JavaScript dipengaruhi oleh Self yang merupakan bahasa pertama dengan pewarisan prototypal. Pada saat itu warisan klasik adalah hal yang paling disukai, pertama kali diperkenalkan di Simula. Namun warisan klasik terlalu rumit. Kemudian David Ungar dan Randall Smith memiliki pencerahan setelah membaca GEB - "Acara yang paling spesifik dapat berfungsi sebagai contoh umum dari kelas acara." Mereka menyadari bahwa kelas tidak diperlukan untuk pemrograman berorientasi objek. Maka dari itu Self dilahirkan. Untuk mengetahui bagaimana pewarisan prototypal lebih baik daripada warisan klasik baca ini: stackoverflow.com/a/16872315/783743 =)
Aadit M Shah
@AaditMShah Apa / siapa itu GEB?
Alex
3
@Alex GEB adalah buku yang ditulis oleh Douglas Hofstadter. Ini adalah singkatan dari Gödel Escher Bach. Kurt Gödel adalah seorang ahli matematika. Escher adalah seorang seniman. Bach adalah seorang pianis.
Aadit M Shah

Jawaban:

201

Ada sekitar seratus masalah terminologi di sini, sebagian besar dibangun di sekitar seseorang (bukan Anda) mencoba untuk membuat ide mereka terdengar seperti The Best.

Semua bahasa berorientasi objek harus mampu menangani beberapa konsep:

  1. enkapsulasi data bersama dengan operasi terkait pada data, yang dikenal sebagai anggota data dan fungsi anggota, atau sebagai data dan metode, antara lain.
  2. warisan, kemampuan untuk mengatakan bahwa objek-objek ini hanya seperti itu set objek KECUALI untuk perubahan ini
  3. polymorphism ("banyak bentuk") di mana objek memutuskan sendiri metode apa yang harus dijalankan, sehingga Anda dapat bergantung pada bahasa untuk merutekan permintaan Anda dengan benar.

Sekarang, sejauh perbandingan:

Hal pertama adalah seluruh pertanyaan "kelas" vs "prototipe". Ide awalnya dimulai di Simula, di mana dengan metode berbasis kelas setiap kelas mewakili satu set objek yang berbagi ruang keadaan yang sama (baca "nilai yang mungkin") dan operasi yang sama, sehingga membentuk kelas ekivalensi. Jika Anda melihat kembali Smalltalk, karena Anda dapat membuka kelas dan menambahkan metode, ini sama dengan apa yang dapat Anda lakukan di Javascript.

Kemudian bahasa OO ingin dapat menggunakan pemeriksaan tipe statis, jadi kami mendapat gagasan tentang kelas tetap yang ditetapkan pada waktu kompilasi. Dalam versi kelas terbuka, Anda memiliki lebih banyak fleksibilitas; di versi yang lebih baru, Anda memiliki kemampuan untuk memeriksa beberapa jenis kebenaran di kompiler yang seharusnya memerlukan pengujian.

Dalam bahasa "berbasis kelas", penyalinan itu terjadi pada waktu kompilasi. Dalam bahasa prototipe, operasi disimpan dalam struktur data prototipe, yang disalin dan dimodifikasi pada saat dijalankan. Namun secara abstrak, sebuah kelas masih merupakan kelas ekivalensi dari semua objek yang memiliki ruang dan metode yang sama. Saat Anda menambahkan metode ke prototipe, Anda secara efektif membuat elemen kelas kesetaraan baru.

Sekarang, mengapa melakukan itu? terutama karena itu membuat mekanisme yang sederhana, logis, elegan pada saat run time. sekarang, untuk membuat objek baru, atau untuk membuat kelas baru, Anda hanya perlu melakukan salinan yang dalam, menyalin semua data dan struktur data prototipe. Anda mendapatkan lebih banyak warisan dan polimorfisme secara gratis: pencarian metode selalu terdiri dari meminta kamus untuk penerapan metode dengan nama.

Alasan yang berakhir pada skrip Javascript / ECMA pada dasarnya adalah bahwa ketika kami memulai ini 10 tahun yang lalu, kami berhadapan dengan komputer yang kurang kuat dan browser yang kurang canggih. Memilih metode berbasis prototipe berarti penerjemah bisa sangat sederhana sambil mempertahankan sifat yang diinginkan dari orientasi objek.

Charlie Martin
sumber
1
Benar, apakah paragraf itu terbaca seolah saya maksud sebaliknya? Dahl dan Nyqvist datang dengan "kelas" sebagai koleksi hal-hal dengan metode tanda tangan yang sama.
Charlie Martin
1
Apakah perubahan itu mengatakan lebih baik?
Charlie Martin
2
Tidak, maaf, CLOS berasal dari dreamsongs.com/CLOS.html akhir 80- an dari 1980 en.wikipedia.org/wiki/Smalltalk dan Simula dengan orientasi objek penuh dari 1967-68 en.wikipedia.org/wiki/Simula
Charlie Martin
3
@Stephano, Mereka tidak begitu berbeda dengan semua itu: Python, Ruby, Smalltalk menggunakan kamus untuk pencarian metode, dan javascript dan Self memiliki kelas. Sampai batas tertentu, Anda bisa berargumen bahwa perbedaannya hanyalah bahwa bahasa yang berorientasi prototipe mengekspos implementasi mereka. Jadi mungkin bagus untuk tidak menjadikannya sebagai Kesepakatan Besar: mungkin lebih seperti argumen antara EMACS dan vi.
Charlie Martin
21
Jawaban yang berguna . +1 Sampah yang kurang berguna di komentar. Maksud saya apakah itu membuat perbedaan apakah CLOS atau Smalltalk adalah yang pertama? Kebanyakan orang di sini bukan sejarawan.
Adam Arold
40

Suatu perbandingan, yang sedikit bias terhadap pendekatan berbasis prototipe, dapat ditemukan dalam makalah Self: The Power of Simplicity . Makalah ini membuat argumen berikut yang mendukung prototipe:

Penciptaan dengan menyalin . Membuat objek baru dari prototipe dilakukan dengan operasi sederhana, menyalin, dengan metafora biologis sederhana, kloning. Membuat objek baru dari kelas dilakukan dengan instantiation, yang mencakup interpretasi informasi format dalam suatu kelas. Instansiasi mirip dengan membangun rumah dari rencana. Menyalin menarik bagi kita sebagai metafora yang lebih sederhana daripada instantiasi.

Contoh modul yang sudah ada sebelumnya . Prototipe lebih konkrit daripada kelas karena mereka adalah contoh objek daripada deskripsi format dan inisialisasi. Contoh-contoh ini dapat membantu pengguna menggunakan kembali modul dengan membuatnya lebih mudah dimengerti. Sistem berbasis prototipe memungkinkan pengguna untuk memeriksa perwakilan tipikal daripada mengharuskannya untuk masuk akal dari deskripsinya.

Dukungan untuk objek satu-of-a-kind . Self menyediakan kerangka kerja yang dapat dengan mudah memasukkan objek satu-satunya dengan perilaku mereka sendiri. Karena setiap objek memiliki nama slot, dan slot dapat menampung status atau perilaku, objek apa pun dapat memiliki slot atau perilaku unik. Sistem berbasis kelas dirancang untuk situasi di mana ada banyak objek dengan perilaku yang sama. Tidak ada dukungan linguistik untuk objek memiliki perilaku uniknya sendiri, dan canggung untuk membuat kelas yang dijamin hanya memiliki satu instance [ pola pikir tunggal ]. Diri tidak mengalami kekurangan ini. Setiap objek dapat disesuaikan dengan perilakunya sendiri. Objek unik dapat menampung perilaku unik, dan "contoh" terpisah tidak diperlukan.

Eliminasi meta-regresi . Tidak ada objek dalam sistem berbasis kelas yang bisa mandiri; objek lain (kelasnya) diperlukan untuk mengekspresikan struktur dan perilakunya. Ini mengarah pada meta-regresi yang tak terbatas secara konseptual: a pointadalah turunan dari kelas Point, yang merupakan turunan dari metaclass Point, yang merupakan turunan dari metametaclass Point, ad infinitum. Di sisi lain, dalam sistem berbasis prototipe suatu objek dapat mencakup perilakunya sendiri; tidak ada objek lain yang diperlukan untuk menghirup kehidupan ke dalamnya. Prototipe menghilangkan meta-regresi.

Self mungkin adalah bahasa pertama yang mengimplementasikan prototipe (itu juga memelopori teknologi menarik lainnya seperti JIT, yang kemudian membuat jalan ke JVM), jadi membaca makalah Self lainnya juga harus instruktif.

Vijay Mathew
sumber
5
RE: Eliminasi meta-regresi: Dalam Common Lisp Object System, yang berbasis kelas, a pointadalah turunan dari kelas Point, yang merupakan turunan dari metaclass standard-class, yang merupakan turunan dari dirinya sendiri, ad finitum.
Max Nanasy
Tautan ke makalah mandiri sudah mati. Tautan kerja: Mandiri: Kekuatan Kesederhanaan | Bibliografi Mandiri
user1201917
24

Anda harus membaca buku hebat tentang JavaScript oleh Douglas Crockford . Ini memberikan penjelasan yang sangat baik tentang beberapa keputusan desain yang diambil oleh pembuat JavaScript.

Salah satu aspek desain penting dari JavaScript adalah sistem pewarisan prototipalnya. Objek adalah warga negara kelas pertama dalam JavaScript, sedemikian rupa sehingga fungsi reguler juga diimplementasikan sebagai objek (objek 'Fungsi' tepatnya). Menurut pendapat saya, ketika awalnya dirancang untuk berjalan di dalam browser, itu dimaksudkan untuk digunakan untuk membuat banyak objek tunggal. Di browser DOM, Anda menemukan jendela itu, mendokumentasikan dll semua objek tunggal. Selain itu, JavaScript adalah bahasa dinamis yang diketik secara longgar (tidak seperti Python yang diketik dengan kuat, bahasa dinamis), sebagai akibatnya, konsep ekstensi objek diimplementasikan melalui penggunaan properti 'prototipe'.

Jadi saya pikir ada beberapa pro untuk OO berbasis prototipe seperti yang diterapkan dalam JavaScript:

  1. Cocok di lingkungan yang diketik secara longgar, tidak perlu mendefinisikan tipe eksplisit.
  2. Membuatnya sangat mudah untuk menerapkan pola tunggal (bandingkan JavaScript dan Java dalam hal ini, dan Anda akan tahu apa yang saya bicarakan).
  3. Memberikan cara menerapkan metode objek dalam konteks objek yang berbeda, menambah dan mengganti metode secara dinamis dari objek, dll. (Hal-hal yang tidak mungkin dilakukan dalam bahasa yang diketik dengan kuat).

Berikut adalah beberapa kontra dari O prototypal:

  1. Tidak ada cara mudah mengimplementasikan variabel pribadi. Mungkin untuk mengimplementasikan vars pribadi menggunakan sihir Crockford menggunakan penutupan , tetapi jelas tidak sepele seperti menggunakan variabel pribadi di katakanlah Java atau C #.
  2. Saya belum tahu bagaimana menerapkan beberapa warisan (untuk apa nilainya) di JavaScript.
Amit
sumber
2
Cukup gunakan konvensi penamaan untuk vars pribadi, seperti yang dilakukan Python.
aehlke
1
di js cara untuk melakukan vars pribadi adalah dengan penutupan, dan itu terlepas dari jenis warisan yang Anda pilih.
Benja
6
Crockford telah melakukan banyak hal untuk merusak JavaScript, di mana bahasa scripting yang cukup sederhana telah berubah menjadi daya tarik masterbatory dengan internalnya. JS tidak memiliki cakupan kata kunci pribadi yang sebenarnya atau pewarisan berganda yang benar: jangan coba memalsukannya.
Hal50000