Prototip miras, pratik olarak klasik mirastan ne kadar farklıdır?


27

Kalıtım, Polimorfizm ve Kapsülleme, OOP'nin en belirgin üç önemli özelliğidir ve bunlardan, kalıtımın bu günlerde yüksek kullanım istatistiklerine sahiptir. JavaScript öğreniyorum ve burada hepsi prototip mirası olduğunu söylüyorlar ve her yerdeki insanlar bunun klasik mirastan çok farklı bir şey olduğunu söylüyor .

Ancak, pratik kullanım açısından farklılıklarının ne olduğunu anlayamıyorum. Başka bir deyişle, bir temel sınıfı (prototip) tanımladığınızda ve ondan bazı alt sınıfları türettiğinizde, her ikiniz de temel sınıfınızın işlevlerine erişebilirsiniz ve türetilmiş sınıflardaki işlevleri artırabilirsiniz. Kalıtımın amaçlanan sonucu olarak söylediklerimi göz önünde bulundurursak, neden prototip veya klasik versiyon kullanıyoruz?

Kendimi daha fazla açıklığa kavuşturmak için prototip ve klasik mirasın fayda ve kullanım şekillerinde bir fark görmüyorum. Bu da neden farklı olduklarını öğrenmekle ilgilenmediğimde, ikisi de aynı şeyi yapan OOAD ile sonuçlandı. Pratik (teorik olarak değil) prototip mirası klasik mirastan ne kadar farklıdır?

Yanıtlar:


6

JS OO hakkında son blog yazısı

Karşılaştığınız şeyin , JavaScript ve klasik OO'daki klasik OO öykünmesi olduğuna ve tabii ki hiçbir fark göremediğinize inanıyorum .

Feragatname: "prototypal OO" ile ilgili tüm referansları "JavaScript'teki prototypal OO" ile değiştirin. Ben'in veya başka bir uygulamanın özelliklerini bilmiyorum.

Ancak prototip OO farklıdır. Prototiplerle yalnızca nesnelere sahipsiniz ve nesneleri yalnızca başka nesnelerin prototip zincirine enjekte edebilirsiniz. Bir nesne üzerindeki bir özelliğe ne zaman erişirseniz o nesneyi ve prototip zincirindeki tüm nesneleri ararsınız.

Prototip OO için hiçbir kapsülleme kavramı yoktur. Kapsülleme bir kapsam, kapanış ve birinci sınıf fonksiyonların bir özelliğidir ancak prototip OO ile ilgisi yoktur. Miras kavramı da yoktur; insanların “miras” dedikleri şey aslında sadece polimorfizmdir.

Bununla birlikte, polimorfizmi var.

Örneğin

var Dog = {
  walk: function() { console.log("walks"); }
}

var d = Object.create(Dog);
d.walk();

Açıkça dyönteme erişimi vardır Dog.walkve bu polimorfizm sergiler.

Yani aslında büyük bir fark var . Sadece polimorfizm var.

Ancak, belirtildiği gibi, eğer bunu yapmak istiyorsanız (neden yapacağınız hakkında hiçbir fikrim yok) , JavaScript’te klasik OO’yu taklit edebilir ve (sınırlı) kapsülleme ve kalıtıma erişebilirsiniz.


1
@Rayons, Google prototipik miras için ve prototip mirasın ortaya çıktığını göreceksiniz . Yahoo!
Saeed Neamati

@ Saeed miras belirsiz bir terimdir ve yaygın olarak kötüye kullanılır. "Miras" ile ne demek "polimorfizm" olarak adlandırıyorum. Tanımlar çok belirsiz.
Raynos

Hayır @Rayons, ben kelime anlamı Prototypal doğru terim, değil prototip . Miras hakkında konuşmadım :)
Saeed Neamati

1
@Saeed bu yazımlardan biri, aklımdan yeni çıkmış. Buna dikkat etmiyorum
Raynos

1
Hmm .. terminoloji. Ick. Javascript nesnelerinin prototipleriyle “delegasyon” ile ilgili olduğunu söyleyebilirim. Polimorfizm, verilen bir ismin farklı nesneler için farklı kodlara işaret edebileceğine dayanarak daha düşük bir endişe kaynağı gibi görünüyor.
Sean McMillan

15

Klasik miras, herhangi bir durum olmadan davranışı ebeveyn sınıfından miras alır. Nesnenin başlatıldığı anda davranışı devralır.

Prototip devralma davranış ve durumu ana nesneden devralır. Nesne çağrıldığı anda davranışı ve durumu devralır. Üst nesne çalışma zamanında değiştiğinde, alt nesnelerin durumu ve davranışı etkilenir.

Prototip kalıtımın "avantajı", tüm nesnelerinizin başlatılmasından sonra durumu ve davranışı "düzeltebilmeniz" dir. Örneğin, Ext JS çerçevesinde, çerçeve oluşturulduktan sonra çerçevenin çekirdek bileşenlerine yama yapan "geçersiz kılmaları" yüklemek yaygındır.


4
Uygulamada, eğer devralırsanız, kendinizi incinmiş bir dünyaya hazırlarsınız. Miras kalan devlet, başka bir nesne üzerinde yaşıyorsa paylaşılacaktır.
Sean McMillan

1
Javascript'te gerçekten durumdan ayrı bir davranış kavramı olmadığı aklıma geliyor. Yapıcı işlevinin yanı sıra, tüm davranışlar, herhangi bir diğer durumdaki gibi nesne sonrası yaratım sonrası atanabilir / değiştirilebilir.
Joeri Sebrechts

Yani Python'un klasik mirası yok mu? Olursa class C(object): def m(self, x): return x*2ve sonra instance = C()koşarsam instance.m(3)anlarım 6. Sonra değiştirmek Ama eğer Cbu yüzden C.m = lambda s, x: x*xben koşmak instance.m(3)şimdi olsun 9. Aynı şey class D(C)bir yöntem yapıp değiştirdiğimde , değiştirilen yöntemi de aldığı Cdurumlarda geçerli olur D. Yanlış anlıyor muyum yoksa bu, Python'un tanımınıza göre Klasik mirasa sahip olmadığı anlamına mı geliyor?
mVChr

@mVChr: ​​Davranışı miras alıyorsunuz ve bu durumda, klasik mirasa işaret eden bir durum belirtmiyorsunuz, ancak "nesnenin somutlandığı andaki davranışı miras" tanımımla ilgili bir meseleye işaret ediyor. Tanımı nasıl düzelteceğimi bilemiyorum.
Joeri Sebrechts

9

Birincisi: Çoğu zaman, nesneleri tanımlayacaksınız, tanımlayamayacaksınız, ve nesneleri kullanmak her iki paradigma altında da aynı.

İkincisi: Çoğu prototip ortam, sınıf tabanlı ortamlarla aynı tür bölünme kullanır - örnek üzerindeki değişken veriler, kalıtsal yöntemlerle. Yani yine çok az fark var. (Bakınız bu yığın taşması soruya cevabım ve Öz Kağıt Sınıflar olmadan Organizasyon Program . Bak PDF versiyonu için CiteSeer .)

Üçüncüsü: Javascript'in dinamik doğası, kalıtımdan çok daha büyük bir etkiye sahiptir. Bir türün tüm örneklerine temel nesneye atayarak yeni bir yöntem ekleyebildiğim gerçeği temiz, ancak aynı şeyi Ruby'de, sınıfı yeniden açarak da yapabilirim.

Dördüncüsü: Pratik farklar küçük, kullanmayı unutmanın pratik konusu newçok daha büyük - yani, eksik newolanlardan etkilenme ihtimaliniz çok daha fazla , prototip ve klasik kod arasındaki farktan etkileneceğinizden .

Bunların hepsi, prototip ve klasik miras arasındaki pratik fark, beklediğiniz şeylerin (sınıfların), beklediğiniz şeylerinkilerle aynıdır (örnekler.) Bu, sınıflarınızı oluşturabileceğiniz anlamına gelir. parça parça, herhangi bir örnekte kullanacağınız aynı nesne işleme araçlarını kullanarak. (Aslında, sınıf emülasyonu kütüphanelerinin tümü bunu nasıl yapıyor? Aslında diğerleri gibi olmayan bir yaklaşım için, Traits.js dosyasına bakın ). Metaprogramlama yapıyorsanız, bu öncelikle ilginçtir.


yay, en iyi cevap IMO!
Aivar

0

JavaScript'teki prototip devralma aşağıdaki önemli yollardan sınıflardan farklıdır:

Yapıcılar, basitçe çağırmadan çağırabileceğiniz işlevlerdir new:

function Circle (r, x, y) { 
  //stuff here
}
Var c = new Circle();
Circle.call(c, x, y, z); //This works and you can do it over and over again.

Özel değişken veya yöntem yoktur, en iyi ihtimalle bunu yapabilirsiniz:

function Circle (r, x, y) {
  var color = 'red';
  function drawCircle () {
    //some code here with x, y and r
  }
  drawCircle();
  this.setX = function (x_) {
    x = x_;
    drawCircle();
  }

}
Circle.prototype.getX = function () {
   //Can't access x!
}

Önceki örnekte, sahte özel değişkenlere ve yöntemlere başvurursanız, ek bir sınıf genişletemezsiniz ve ek olarak, ilan ettiğiniz her türlü yeni yöntem her seferinde yeniden oluşturulacaktır.


"Sınıf" ı anlamlı şekilde genişletebilirsiniz. Sadece yerel değişkenleri erişemez color, r, x, yve drawCirclesözcüksel kapsamına bağlanmıştırCircle
Raynos

Doğru, yapabilirsiniz, ancak bunu bir örnek oluşturduğunuzda oluşturulan bağlama eklenmiş bir grup 'public' yöntem oluşturmadan yapamazsınız.
Bjorn

Bu orada kullandığınız çok garip bir kalıp. Circle.call()yapıcı olarak mı? "İşlevsel nesneleri" (yanıltıcı bir şeyler ...) tanımlamaya çalışıyorsunuz gibi görünüyor
Sean McMillan

Yapabileceğim bir şey değil, sadece yapıcıyı tekrar tekrar JavaScript ile çağırmanın mümkün olduğunu söylüyorum ama geleneksel sınıflara sahip dillerde değil.
Bjorn

1
Fakat bu farklılıklar nasıl 'önemli'? Nesneleri 'yeni' kullanarak 'önemli' olarak kullanmadan, sadece küçük bir sözdizimi farkı kullanarak bir işlev çağırarak nesneler yapmayı görmüyorum. Aynı şekilde, özel değişkenlere sahip olmamak temelde farklı değildir, sadece küçük bir farktır. Ayrıca, olabilir açıkladığınız şekilde özel değişkenler (benzer bir şey) var.
Roel
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.