JavaScript'te prototip programlama ne zaman kullanılır?


15

Projeler için basit widget'lar geliştirmek için aşağıdaki şekilde biraz zaman harcadım:

var project = project || {};

(function() {

  project.elements = {
    prop1: val1,
    prop2: val2
  }

  project.method1 = function(val) {
    // Do this
  }

  project.method2 = function(val) {
    // Do that
  }

  project.init = function() {
    project.method1(project.elements.prop1)
    project.method2(project.elements.prop2)
  }
})()

project.init();

Ama biçimimi şu şekilde değiştirmeye başladım:

function Project() {
  this.elements = {
    prop1: val1,
    prop2: val2
  }

  this.method_one(this.elements.prop1);
  this.method_two(this.elements.prop2);
}

Project.prototype.method_one = function (val) {
  // 
};

Project.prototype.method_two = function (val) {
  //
};

new Project();

Verilmiş, bunlar aptal örneklerdir, bu yüzden akselin etrafına sarmayın. Fakat fonksiyonel fark nedir ve ne zaman birini seçmeliyim?


Proje kapsamı terk etmediği için ilk kod örneğinizin işe yaramayacağını düşünüyorum. JS'de kalıtım kullanmak için prototipleme kullanırsınız. İlk örnek projeyi genişletmek için değildir, bu nedenle yeniden kullanılabilirlik sınırlı olabilir.
Aitch

Evet, projectbeyanı yanlışlıkla işlevin içine koydum . Güncellenmiş.
JDillon522

burada aynı. ilk örnek statik, ikincisi nesne yönelimlidir.
Aitch

1
Nesnenin yalnızca BİR örneğini kullanıyorsanız, prototypal tanımını kullanmak için hiçbir neden yoktur. Ve ihtiyacınız olan şey bir modül biçimidir - bunun için birçok seçenek vardır, bkz: addyosmani.com/writing-modular-js
c69

1
Tekil desen için birincisi Tekil olmayan için ikincisi (1 sınıfın birçok nesnesi olduğunda)
Kokizzu

Yanıtlar:


6

İlk fark şu şekilde özetlenebilir: sınıfın Eşgörünümüthis anlamına gelir . Tanım anlamına gelir .prototype

Diyelim ki şu sınıfa sahibiz:

var Flight = function ( number ) { this.number = number; };

İşte burada this.numbersınıfın her örneğine bağlıyız ve bu mantıklıdır çünkü her Flightbirinin kendi uçuş numarası olmalıdır.

var flightOne = new Flight( "ABC" );
var flightTwo = new Flight( "XYZ" );

Buna karşılık, prototypetüm örnekler tarafından erişilebilen tek bir özellik tanımlar.

Şimdi uçuş numarasını almak istiyorsak, aşağıdaki kod parçasını yazabiliriz ve tüm örneklerimiz bu yeni prototiplenmiş nesneye bir Referans alır .

Flight.prototype.getNumber = function () { return this.number; };

İkinci fark, JavaScript'in bir nesnenin özelliğini aramasıyla ilgilidir. Aradığın zamanObject.whatever , JavaScript ana Object nesnesine (diğer her şeyin miras aldığı nesne) kadar gider ve bir eşleşme bulur bulmaz onu döndürür veya çağırır.

Ancak bu sadece prototip özellikleri için olur. Yüksek seviyelerde bir yeriniz varsathis.whatever , JavaScript bunu bir eşleşme olarak kabul etmez ve aramaya devam eder.

Gerçekte nasıl olduğunu görelim.

İlk olarak [neredeyse] her şeyin JavaScript'teki Nesneler olduğunu unutmayın . Bunu dene:

typeof null

Şimdi bir içinde ne olduğunu görelim Object(Büyük Harfe Ove .sonuna dikkat edin ). Google Chrome'un Geliştirici Araçları'na girdiğinizde, .söz konusu nesnenin içindeki kullanılabilir özelliklerin bir listesini alırsınız.

Object.

Şimdi aynı şeyi yapın Function:

Function.

nameYöntemi fark edebilirsiniz . Sadece gidip kovun ve ne olacağını görelim:

Object.name
Function.name

Şimdi bir fonksiyon oluşturalım:

var myFunc = function () {};

Ve nameburada da yöntemi bulup bulamadığımızı görelim :

myFunc.name

Boş bir dize almalısın, ama sorun değil. Hata veya İstisna almamalısınız.

Şimdi o tanrıya bir şey ekleyelim Objectve başka yerlerde de alıp almadığımızı görelim mi?

Object.prototype.test = "Okay!";

Ve işte gidiyorsunuz:

Object.prototype.test
Function.prototype.test
myFunc.prototype.test

Her durumda görmelisin "Okay!".

Her yöntemin avantajları ve dezavantajları ile ilgili olarak, prototip oluşturmayı bir şeyler yapmanın "daha verimli" bir yolu olarak düşünebilirsiniz, çünkü her nesnede tüm özelliği kopyalamak yerine her örnekte bir referans tutar. Öte yandan , sebebini gerçekten haklı gösterene kadar büyük bir hayır-hayır olan Sıkı Kuplaj örneğidir .thisbağlamla ilgili olduğu için oldukça karmaşıktır. İnternette ücretsiz olarak birçok iyi kaynak bulabilirsiniz.

Bununla birlikte, her iki yol da sadece dil araçlarıdır ve gerçekten size ve neyin daha iyi uyduğunu seçmek için çözmeye çalıştığınız soruna bağlıdır.

Bir sınıfın her örneğiyle alakalı olması için bir özelliğiniz olması gerekiyorsa, kullanın this. Her örnekte aynı işlevi görmek için bir özelliğe sahip olmanız gerekiyorsa, kullanın prototype.

Güncelleme

Örnek snippet'lerinizle ilgili olarak, birincisi Singleton örneğidir , bu nedenle thisnesne gövdesi içinde kullanmak mantıklıdır . Örneğinizi bu şekilde modüler hale getirerek de geliştirebilirsiniz (ve her zaman da kullanmanıza gerek yoktur this).

/* Assuming it will run in a web browser */
(function (window) {
    window.myApp = {
        ...
    }
})( window );

/* And in other pages ... */
(function (myApp) {
    myApp.Module = {
        ...
    }
})( myApp );

/* And if you prefer Encapsulation */
(function (myApp) {
    myApp.Module = {
         "foo": "Foo",
         "bar": function ( string ) {
             return string;
         },
         return {
             "foor": foo,
             "bar": bar
         }
    }
})( myApp );

İkinci snippet'iniz pek mantıklı değil çünkü önce kullanıyorsunuz thisve daha sonra onu hacklemeye çalışıyorsunuz prototype, bu işe yaramıyor çünkü thisöncelikli prototype. Bu koddan beklentilerinizin ne olduğundan ve nasıl çalıştığından emin değilim, ancak bunu yeniden düzenlemenizi tavsiye ederim.

Güncelleme

thisÖncelik almayı detaylandırmak için prototypesize bir örnek gösterebilir ve bunun nasıl açıklanabileceğini söyleyebilirim, ancak bunu destekleyecek harici bir kaynağım yok.

Örnek çok basit:

var myClass = function () { this.foo = "Foo"; };
myClass.prototype.foo = "nice try!";
myClass.prototype.bar = "Bar";

var obj = new myClass;
obj.foo;     // Still contains "Foo" ...
obj.bar;     // Contains "Bar" as expected

Açıklama, bildiğimiz gibi this, bağlamla ilgilidir. Dolayısıyla bağlam hazır olana kadar ortaya çıkmayacak. Bağlam ne zaman hazır olur? Yeni örnek oluşturulurken! Şimdi gerisini tahmin etmelisin! Bu, bir prototypetanım olmasına rağmen, thisöncelikli olmak için daha mantıklı olduğu anlamına gelir, çünkü her şey o anda yaratılan yeni örnekle ilgilidir.


Bu kısmen destansı bir cevap! İki yöntemi karşılaştırarak ve kıyaslayarak daha ayrıntılı bir ayrıntıya girebilir misiniz? İlk iki paragrafınız hangi tasarım yönteminden bahsettiğinizi karıştırıyor. Egzersiziniz mükemmel! Bu şekilde prototip yapmanın gücü hakkında hiç düşünmedim. Ayrıca her bir yöntemi ne zaman kullanacağınıza dair yarı ayrıntılı bir vaka kullanımı örneği verebilir misiniz? Tekrar teşekkürler, bu harika.
JDillon522

@ JDillon522 Bunu duyduğuma sevindim. Önümüzdeki saatlerde güncellemeye çalışacağım!
16'da

@ JDillon522 Kısa bir güncelleme yaptınız. Umarım bu sefer daha açık olacak.
53777A

@ JDillon522 Örnek parçacıklarınız hakkında biraz daha ...
53777A

Güzel singleton örneği. Bu yüzden thisaptal prototip örneğinde kullandım çünkü thisyöntemleri de dahil olmak üzere kendi özelliklerini ifade ediyor. Ben kod hakkında okuyarak en iyi öğrenmiyorum, ama daha fazla kod bakarak. ( MDN'nin üzerinde biraz , Object Playground (şaşırtıcı) ve diğerleri). " thisÖnceliği alır " hakkında ne demek istediğinizi açıklayan bir şeye işaret edebilir misiniz prototype? Daha fazla bakmak istiyorum.
JDillon522
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.