Prototipik kalıtsal çocuk sınıfı neden başka bir çocuk sınıfının örneğidir?

Belki de bunu yanlış yapıyorum. Bir temel sınıf ve o sınıftan miras kalan iki sınıf kurmak istiyorum. Bununla birlikte, bana bir çocuğun diğer çocuğun bir ürünü olduğunu söyler ... bu doğru olamaz, değil mi? Burada neyi yanlış yapıyorum?

function BaseClass(){}
function Child1(){}

Child1.prototype = BaseClass.prototype;
Child1.prototype.constructor = Child1;

function Child2(){}
Child2.prototype = BaseClass.prototype;
Child2.prototype.constructor = Child2;

console.log((new Child1() instanceof Child2));//true
0
JS'de kalıtımın birçok yolunu kullanmanın iyi bir kaynağı: 3site.eu/doc
katma yazar Cᴏʀʏ, kaynak

4 cevap

Her iki sınıfın prototipini tam olarak aynı nesneye ("BaseClass.prototype") ayarladınız ve "constructor" özelliğini "Child2" ye ayarladınız. Başka bir deyişle, "Child1.prototype" ve "Child2.prototype" aynıdır, bu nedenle kodunuzda yalnızca bir "kurucu" özelliği vardır ve "Child2" olmaktan çıkar.

Belki bu prototipleri BaseClass'ın örneklerini olarak ayarlamak istersiniz?

Child1.prototype = new BaseClass();
Child1.prototype.constructor = Child1;

Child2.prototype = new BaseClass();//a different object
Child2.prototype.constructor = Child2;

(@Raynos, prototip değeri gibi ince problemlere yol açabileceğine dikkat çekiyor, böylece cevabı kendi yaklaşımında kullanmayı tercih edebilirsiniz.)

3
katma
.prototype = new X() 'dan kaçınmanız gerekir. .prototype ' ı X'in bir örneği olarak başlatmak istemezsiniz. (yani kurucuyu arama!)
katma yazar Raynos, kaynak
@ShyGuy onları o zaman başlatmazsın, o çocuğun yapıcısında yaparsın.
katma yazar Raynos, kaynak
@Pointy :( çok sayıda nesne çerçevesi "init" öneriyor çünkü onlar kirli hackler.Yeni miras alırken sadece kurucuları kullanmıyorsunuz (ipucu: Object.create istediğiniz şeyi yapar).
katma yazar Raynos, kaynak
@Pointy Evet, birisi JavaScript dediğinde "ES5" düşünmenin bu kötü alışkanlığım var. Sadece onu kapatamıyorum!
katma yazar Raynos, kaynak
Temel sınıf kurucunuzun argümanları olduğunda ne olur? Onları hemen oradan başlatmak için mi ihtiyacınız var? Benim gerçek çocuk sınıf kodum BaseClass.call (bu 'argüman1', 'argüman2') çağrısı var; yapıcısında.
katma yazar Paul, kaynak
Tamam @Raynos evet bu muhtemelen doğrudur; Ben bu tür konularla uğraşmak için yeterince sık bir şey yapmıyorum :-) Bir ekleyeceğim.
katma yazar Pointy, kaynak
@ShyGuy Bu yüzden birçok nesne çerçevesinin, "init" işlevini çağırmak için bir sözleşme kullandığını düşünüyorum.
katma yazar Pointy, kaynak
@Raynos bunu kesinlikle benden daha çok biliyorsunuz :-) Çok fazla JavaScript yazmama rağmen JavaScript'te "object-y" kodu yazmamıştım. (Ayrıca, Object.create bir ES5 olayı değil midir? Muhtemelen MDN'de bir çok doluluk var.)
katma yazar Pointy, kaynak

Child1.prototype = BaseClass.prototype;

Should be Child1.prototype = Object.create(BaseClass.prototype)

You don't want the prototype object to be the same, you want a new prototype object that inherits from BaseClass

Canlı Örnek

Disclaimer: Object.create is ES5, use the ES5-shim for legacy platform support.

Size daha kapsamlı bir örnek vermek için:

// Create base prototype
var Base = {
  method: function() {
    return this.things;
  },
  constructor: function (things) {
    this.things = things;
  }
};
// Link constructor and prototype
Base.constructor.prototype = Base;

// Create child prototype that inherits from Base
var Child = Object.create(Base);
// overwrite constructor
Child.constructor = function (things) {
  things++;
  Base.constructor.call(things);
}
// Link constructor and prototype
Child.constructor.prototype = Child;

// Swap prototype and constructor around to support new
ChildFactory = Child.constructor;

var c = new ChildFactory(41);
console.log(c.method());//42

Görme:

var Base = {...}

Burada sadece yöntem ve özelliklerle bir nesne oluşturuyoruz. Bu nesnenin bir örneği oluşturabilmek istiyoruz. Yani Base bir "class" dır ve tüm metodları ve özelliklerine örneklerden erişilebilir ( constructor dahil).

Base.constructor.prototype = Temel;

Prototip nesnesiyle birlikte ConstructorFunction.prototype nesnesinin yeni bir örneğini verecek new ile çağırabileceğiniz bir işlev olan "Oluşturucu işlevi" ni bağlamanız gerekir. . Bu temelde elle yapmanız gereken bir yapıştırıcıdır, çünkü ES bunu sizin için yapmaz.

Bunu yapmayı unuttuysanız, constructor işlevinin ( X.constructor olan), örnekleri devralmak için .prototype özelliği yoktur.

var Çocuk = Object.create (Temel);

[[Prototype]] Base olan yeni bir nesne oluşturun. Bu temel olarak prototip zincirinizin başlangıcıdır.

Child -> ([[Prototype]] = Base) -> ([[Prototype]] = Object.prototype) -> null

Child.x = ...

Şimdi, Child nesnesine, Child'ın miras yöntemlerinin örnekleri olan özellikleri ekliyoruz. Temel olarak, devralmak için yeni bir prototip nesne oluşturuyoruz. Tüm örnekler yöntemleri paylaşacak ve yöntemleri prototip zincirinde ( Base dahil) paylaşacaktır.

ChildFactory = Child.constructor;

yeni anahtar sözcüğü, yalnızca constructor işlevlerinde çalışır ve prototip nesneleri değil, temel olarak "prototip nesne değişkenini yapıcı işlev değişkenine dönüştürmemiz" gerekmemiz gerekir.

Şahsen "sınıflar" oluştururken, prototip nesnelerini doğrudan işlemek için gerçekten hoş buluyorum ve örnekler oluştururken, yapıcı işlevlerini kullanması keyifli.

Now when we call var c = new Child(41);

Tanımladığımız kurucu işlevini şeyler 'i artıracak, ardından temel kurucuyu çağıracak.

Bu noktada notun c prototip zinciri gibi görünüyor

c -> ([[Prototype]] = Child) 
  -> ([[Prototype]] = Base) 
  -> ([[Prototype]] = Object.prototype) 
  -> null
2
katma
Teşekkürler! Bu bir çekicilik gibi çalışır ... Sahne arkasında neler olduğunu görmek için daha fazla okuma yapmak zorunda kalacağım. Net olarak kalıtımın nasıl yapılacağı konusunda pek çok farklı örnek var ve hepsi sert bitlerden kaçınmak için parametresiz kuruculara sahip gibi görünüyorlar :)
katma yazar Paul, kaynak

Yeni Child1() nesnesinin "Child1" yapıcısı tarafından oluşturulup oluşturulmadığını kontrol etmek anlamına gelmez. instanceof operatörü sadece bir nesne prototipini alır - (yeni Child1 ()). [[Prototip]] ve prototip zincirindeki varlığını kontrol eder, “Child1” den incelemeye katılır. .prototip". Operatör instanceof , yapıcının dahili [[HasInstance]] yöntemi ile etkinleştirilir. Yani kodunuzu aşağıdaki şekilde değiştirmeniz gerekiyor:

function BaseClass(){}
function Child1(){}

Child1.prototype = new BaseClass();
Child1.prototype.constructor = Child1;

function Child2(){}
Child2.prototype = new BaseClass();
Child2.prototype.constructor = Child2;
console.log((new Child1() instanceof Child2));//false

Ve javascript’te OOP’un doğru olarak uygulanması

1
katma

Prototip atarsanız, bunun tamamen üzerine yazmanız anlamına gelmez mi? Böylece Child1 ve Child2 aslında alt sınıflar yerine BaseClass nesneleri haline gelir.

Ayrıca bkz. http://www.zipcon.net/~swhite /docs/computers/languages/object_oriented_JS/inheritance.html . JS'deki uygun OO oldukça fazla çaba harcar.

1
katma