prototip tabanlı ve sınıf tabanlı kalıtım


208

JavaScript'te her nesne aynı zamanda bir örnek ve bir sınıftır. Kalıtım yapmak için, herhangi bir nesne örneğini prototip olarak kullanabilirsiniz.

Python, C ++, vb. 'De ayrı kavramlar olarak sınıflar ve örnekler vardır. Kalıtım yapmak için, daha sonra türetilmiş örnekler üretmek için kullanılabilecek yeni bir sınıf oluşturmak için temel sınıfı kullanmanız gerekir.

JavaScript neden bu yönde ilerledi (prototip tabanlı nesne yönlendirmesi)? prototip tabanlı OO'nun geleneksel, sınıf tabanlı OO'ya göre avantajları (ve dezavantajları) nelerdir?


10
JavaScript, prototip kalıtımına sahip ilk dil olan Benlikten etkilendi. O zamanlar klasik kalıtım, ilk olarak Simula'da tanıtılan tüm öfke idi. Ancak klasik kalıtım çok karmaşıktı. Sonra David Ungar ve Randall Smith GEB'i okuduktan sonra bir tezahürü vardı - "En spesifik olay, bir olay sınıfının genel bir örneği olabilir." Nesneye yönelik programlama için sınıfların gerekli olmadığını fark ettiler. Böylece Öz doğdu. Prototipal kalıtımın klasik kalıtımdan daha iyi olduğunu bilmek için şunu okuyun: stackoverflow.com/a/16872315/783743 =)
Aadit M Shah

@AaditMShah Nedir / kimdir GEB?
Alex

3
@Alex GEB, Douglas Hofstadter tarafından yazılmış bir kitaptır. Gödel Escher Bach'ın kısaltmasıdır. Kurt Gödel bir matematikçiydi. Escher bir sanatçıydı. Bach bir piyanistti.
Aadit M Shah

Yanıtlar:


201

Burada, çoğunlukla En İyi gibi fikirlerini ortaya çıkarmaya çalışan birinin (sizin değil) etrafında inşa edilen yaklaşık yüz terminoloji sorunu var.

Tüm nesne yönelimli dillerin çeşitli kavramlarla başa çıkabilmesi gerekir:

  1. verilerin, veri elemanları ve üye işlevleri olarak bilinen ya da veri ve yöntemler olarak bilinen veriler üzerinde ilişkili işlemler ile birlikte kapsüllenmesi.
  2. miras, bu nesnelerin bu değişiklikler hariç, diğer nesne kümesine benzediğini söyleme yeteneği
  3. bir nesnenin hangi yöntemlerin çalıştırılacağına kendisi karar verdiği polimorfizm ("birçok şekil"), böylece isteklerinizi doğru yönlendirmek için dile bağlı olabilirsiniz.

Şimdi, karşılaştırma kadar:

İlk şey bütün "sınıf" ve "prototip" sorusudur. Fikir başlangıçta Simula'da başladı, burada sınıf tabanlı bir yöntemle her sınıf aynı durum alanını ("olası değerleri" okuyun) ve aynı işlemleri paylaşan ve böylece bir denklik sınıfı oluşturan bir dizi nesneyi temsil etti. Smalltalk'a tekrar bakarsanız, bir sınıf açıp yöntemler ekleyebileceğinizden, bu etkili bir şekilde Javascript'te yapabileceklerinizle aynıdır.

Daha sonra OO dilleri statik tip kontrolünü kullanmak istediğinden, derleme zamanında sabit bir sınıf seti fikrini aldık. Açık sınıf versiyonunda daha fazla esnekliğe sahiptiniz; daha yeni sürümde, derleyicide aksi takdirde test yapılması gereken bazı doğruluk türlerini kontrol etme olanağınız vardı.

"Sınıf tabanlı" bir dilde, bu kopyalama derleme zamanında gerçekleşir. Bir prototip dilde işlemler, çalışma zamanında kopyalanan ve değiştirilen prototip veri yapısında saklanır. Soyut olarak, yine de, bir sınıf hala aynı durum alanını ve yöntemlerini paylaşan tüm nesnelerin denklik sınıfıdır. Prototipe bir yöntem eklediğinizde, etkili bir şekilde yeni bir denklik sınıfının bir öğesini oluşturuyorsunuz.

Şimdi, neden yapıyorsun? çünkü çalışma zamanında basit, mantıklı ve zarif bir mekanizma oluşturur. şimdi, yeni bir nesne oluşturmak veya yeni bir sınıf oluşturmak için, tüm verileri ve prototip veri yapısını kopyalayarak derin bir kopya gerçekleştirmeniz yeterlidir. Kalıtım ve polimorfizmi az ya da çok ücretsiz olarak elde edersiniz: yöntem arama her zaman ada göre bir yöntem uygulaması için bir sözlük istemekten oluşur.

Javascript / ECMA betiği ile sonuçlanan nedeni temelde bu 10 yıl önce başlarken, çok daha az güçlü bilgisayarlar ve çok daha az karmaşık tarayıcılar ile uğraşmak oldu. Prototip tabanlı yöntemin seçilmesi, yorumlayıcının nesne yöneliminin arzu edilen özelliklerini korurken çok basit olabileceği anlamına gelir.


1
Doğru, bu paragâh sanki başka türlü demek istediğim gibi mi okuyor? Dahl ve Nyqvist, aynı yöntem imzası olan şeylerin toplanması olarak "sınıf" bulmuşlardır.
Charlie Martin

1
Bu değişiklik daha mı iyi diyor?
Charlie Martin

2
Üzgünüm, Hayır, CLOS geç 80 'dan dreamsongs.com/CLOS.html 1980 den Smalltalk en.wikipedia.org/wiki/Smalltalk tam nesne yönelimi ile ve Simula 1967-1968 den en.wikipedia.org/wiki/Simula
Charlie Martin

3
@Stephano, Hepsi o kadar da farklı değil: Python, Ruby, Smalltalk yöntem aramak için sözlükler kullanıyor ve javascript ve Self sınıfları var. Bir dereceye kadar, aradaki farkın sadece prototip odaklı dillerin uygulamalarını ortaya koyması olduğunu iddia edebilirsiniz. Yani büyük bir anlaşmaya varmamak muhtemelen iyi: muhtemelen daha çok EMACS ve vi arasındaki tartışma gibi.
Charlie Martin

21
Yararlı cevap . +1 Yorumlarda daha az yararlı önemsiz. Yani CLOS veya Smalltalk'ın ilk olması fark mı ediyor? Buradaki çoğu insan zaten tarihçi değil.
Adam Arold

40

Prototip tabanlı yaklaşıma doğru hafifçe eğilimli bir karşılaştırma, Benlik: Basitliğin Gücü belgesinde bulunabilir . Bu makale prototipler lehine aşağıdaki iddiaları dile getirmektedir:

Kopyalayarak oluşturma . Prototiplerden yeni nesneler yaratmak basit bir işlemle, kopyalama, basit bir biyolojik metaforla, klonlama ile gerçekleştirilir. Sınıflardan yeni nesneler oluşturma, bir sınıftaki biçim bilgilerinin yorumlanmasını içeren örnekleme ile gerçekleştirilir. Örnekleme, bir plandan bir ev inşa etmeye benzer. Kopyalama, bize örneklemeden daha basit bir metafor olarak hitap ediyor.

Önceden var olan modüllere örnekler . Prototipler sınıflardan daha somuttur, çünkü biçim ve başlatma açıklamalarından ziyade nesnelerin örnekleridir. Bu örnekler kullanıcıların daha kolay anlaşılmasını sağlayarak modülleri yeniden kullanmalarına yardımcı olabilir. Prototip tabanlı bir sistem, kullanıcının açıklamasından bir anlam çıkarmasını istemek yerine tipik bir temsilcisi incelemesini sağlar.

Eşi benzeri olmayan nesneler için destek . Öz, kendi davranışlarına sahip türünün tek örneği nesneleri kolayca içerebilecek bir çerçeve sağlar. Her nesne adlandırılmış yuvalara sahip olduğundan ve yuvalar durum veya davranış taşıyabildiğinden, herhangi bir nesne benzersiz yuvalara veya davranışlara sahip olabilir. Sınıf tabanlı sistemler, aynı davranışa sahip birçok nesnenin olduğu durumlar için tasarlanmıştır. Bir nesnenin kendine özgü davranışına sahip olması için dilsel bir destek yoktur ve yalnızca bir örneği olması düşünülen bir sınıf yaratmak gariptir [ think singleton pattern ]. Benlik bu dezavantajların hiçbirinden muzdarip değildir. Herhangi bir nesne kendi davranışı ile özelleştirilebilir. Benzersiz bir nesne benzersiz davranışı tutabilir ve ayrı bir "örnek" gerekli değildir.

Meta-regresyonun ortadan kaldırılması . Sınıf tabanlı bir sistemdeki hiçbir nesne kendi kendine yeterli olamaz; yapısını ve davranışını ifade etmek için başka bir nesneye (sınıfına) ihtiyaç vardır. Kavramsal sonsuz meta kalışın Bu yol açar: bir pointsınıfın bir örneği Point, metaclass bir örneği olan Pointmetametaclass bir örneği olan, Point, sonsuza. Öte yandan, prototip tabanlı sistemlerde bir nesne kendi davranışını içerebilir; hayatını solumak için başka bir nesneye ihtiyaç yoktur. Prototipler meta-gerilemeyi ortadan kaldırır.

Benlik muhtemelen prototipleri uygulayan ilk dildir (ayrıca daha sonra JVM'ye giren JIT gibi diğer ilginç teknolojilere öncülük etmiştir), bu yüzden diğer Benlik belgelerini okumak da öğretici olmalıdır.


5
RE: Meta-regress Eliminasyon: Bir sınıf tabanlı olan Common Lisp Nesne Sistemi, içinde pointsınıfının bir örneğidir Point, metaclass bir örneğidir standard-class, reklam finitum kendisinin bir örneğidir.
Max Nanasy

Öz kağıtlara bağlantılar öldü. Çalışma bağlantıları: Benlik: Sadeliğin Gücü | Bir Öz Bibliyografya
user1201917

24

Douglas Crockford'un JavaScript ile ilgili harika bir kitabına göz atmalısınız . JavaScript yaratıcıları tarafından alınan bazı tasarım kararları hakkında çok iyi bir açıklama sağlar.

JavaScript'in önemli tasarım özelliklerinden biri de prototip kalıtım sistemidir. Nesneler JavaScript'te birinci sınıf vatandaştır, öyle ki düzenli işlevler de nesne olarak uygulanır ('İşlev' nesnesi kesin). Bence, aslında bir tarayıcı içinde çalışacak şekilde tasarlandığında, çok sayıda tekli nesne oluşturmak için kullanılması gerekiyordu. DOM tarayıcısında, pencereyi, belgeyi vb. Tüm singleton nesnelerini bulabilirsiniz. Ayrıca, JavaScript gevşek bir şekilde yazılan dinamik bir dildir (güçlü bir şekilde yazılan Python'un aksine, dinamik bir dil), sonuç olarak, 'prototip' özelliği kullanılarak bir nesne uzantısı kavramı uygulanmıştır.

Bu yüzden JavaScript'te uygulandığı gibi prototip tabanlı OO için bazı artıları olduğunu düşünüyorum:

  1. Gevşek tipteki ortamlar için uygundur, müstehcen tipler tanımlamaya gerek yoktur.
  2. Singleton kalıbının uygulanmasını inanılmaz derecede kolaylaştırır (bu bağlamda JavaScript ve Java'yı karşılaştırın ve neden bahsettiğimi anlayacaksınız).
  3. Bir nesnenin yöntemini farklı bir nesne bağlamında uygulama, bir nesneden dinamik olarak yöntemler ekleme ve değiştirme yöntemleri (güçlü yazılan dillerde mümkün olmayan şeyler) sağlar.

İşte prototypal OO eksilerini:

  1. Özel değişkenleri uygulamanın kolay bir yolu yoktur. Crockford'un sihirbazını kapanışları kullanarak özel değişkenler uygulamak mümkündür , ancak Java veya C # gibi özel değişkenleri kullanmak kadar önemsiz değildir.
  2. Henüz JavaScript'te birden fazla mirasın (değeri için) nasıl uygulanacağını bilmiyorum.

2
Python gibi özel varyasyonlar için bir adlandırma kuralı kullanın.
aehlke

1
js'de özel değişkenler yapmanın yolu kapanışlardır ve seçtiğiniz miras türünden bağımsızdır.
Benja

6
Crockford, JavaScript'e zarar vermek için çok şey yaptı, çünkü oldukça basit bir komut dosyası dili, içselleri ile masterbatory bir büyüye dönüştü. JS'nin gerçek özel anahtar kelime kapsamı veya gerçek çoklu mirası yoktur: bunları taklit etmeye çalışmayın.
Hal50000
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.