JavaScript'te prototip tabanlı sınıf mirası için bir rehber

Bilgisayar dilleri genellikle bir nesnenin miras alınması için bir yol sağlar.
başka bir nesne. Miras alınan nesne, ana nesnesindeki tüm özellikleri içerir. Ek olarak, kendi benzersiz özellik kümesini de belirleyecektir.

JavaScript ipuçları ve kitap duyuruları için beni Twitter'da takip edin.

JavaScript nesneleri prototip tabanlı miras kullanır. Tasarımı, kesinlikle Nesne Yönelimli Programlama dillerinde sınıfsal mirastan mantıksal olarak benzer (ancak uygulamada farklıdır).

Metotlar veya özellikler nesnenin prototipine eklendiğinde, bu nesne ve soyundan kullanım için uygun olduklarını söyleyerek rahatça tanımlanabilir. Ancak bu işlem genellikle perde arkasında gerçekleşir.

Kod yazarken, prototip özelliğine doğrudan dokunmanız bile gerekmez. Split yöntemini çalıştırırken, onu doğrudan değişmez bir dizgeden şöyle çağırırsınız: “hello” .split (“e”) veya bir değişkenden: string.split (“,”);

Sınıf kullandığınızda ve anahtar kelimeleri dahili olarak genişlettiğinizde, JavaScript hala prototip tabanlı miras kullanır. Sadece sözdizimini basitleştirir. Belki de bu yüzden prototip bazlı kalıtımın nasıl çalıştığını anlamak önemlidir. Hala dil tasarımının çekirdeğini oluşturuyor.

Bu yüzden birçok derste sadece String.split yerine String.prototype.split yazısını göreceksiniz. Bu, o nesnenin prototip özelliğine bağlı olduğundan, tür dizesi nesnelerle kullanılabilecek bir yöntem bölmesi olduğu anlamına gelir.

Nesne Türlerinin Mantıksal Hiyerarşisini Oluşturma

Kedi ve Köpek, Hayvandan miras kalan Hayvanlardan miras alınır.

Bir köpek ve bir kedi benzer özellikleri paylaşır. İki farklı sınıf oluşturmak yerine,
basitçe bir sınıf Pet oluşturabilir ve ondan Cat and Dog alabilir. Ancak, Pet sınıfının kendisi de Hayvan sınıfından miras alınabilir.

Başlamadan önce

Prototipleri anlamaya çalışmak, kodlamadan bilgisayar dili tasarımına giden nehri geçmek gibidir. İki tamamen farklı bilgi alanı.

Teknik olarak, sadece sınıfın ışık bilgisi ve anahtar kelimeleri genişletmesi, yazılım yazmak için yeterlidir. Prototipi anlamaya çalışmak, dil tasarımının karanlık köşelerine atılmak gibi bir şey. Ve bazen bu anlayışlı olabilir.

Bu öğretici tek başına yeterli olmayacak. Sadece sizi doğru yöne yönlendirecek bazı önemli şeylere odaklandım.

Kaputun altında

Nesne devralma arkasındaki fikir bir hiyerarşisi için yapı sağlamaktır
benzer nesneler. Ayrıca bir alt nesnenin ebeveyinden “türetilmiş” olduğunu söyleyebilirsiniz.

Prototip zincirleri JavaScript'te nasıl oluşturulur?

Teknik olarak, göründüğü gibi. Bunun hakkında fazla düşünmemeye çalış. Sadece hiyerarşinin en üstünde, Nesne nesnesi olduğunu bilin. Bu yüzden kendi prototipi null değerine işaret ediyor. Üstünde başka hiçbir şey yok.

Prototip Tabanlı Nesne Mirası

JavaScript, prototip olarak bilinen bir şey yoluyla nesne mirasını destekler. Her nesneye ekli prototip adı verilen bir nesne özelliği vardır.

Sınıfla çalışmak ve anahtar kelimeleri genişletmek kolaydır, ancak aslında prototip tabanlı mirasın nasıl çalıştığını anlamak çok da önemsiz değildir. Umarım bu eğitimde en azından bazı sis kaldıracak!

Nesne Yapıcı İşlevleri

Fonksiyonlar nesne yapıcı olarak kullanılabilir. Yapıcı işlevinin adı genellikle normal işlevler arasındaki farkı çizmek için büyük harfle başlar. Nesne yapıcılar, bir nesnenin örneğini oluşturmak için kullanılır.

JavaScript yerleşik nesnelerinden bazıları aynı kuralları izleyerek zaten oluşturuldu. Örneğin, Number, Array ve String, Object'ten devralınır. Daha önce tartıştığımız gibi, bu Object'e eklenmiş herhangi bir özelliğin tüm çocuklarında otomatik olarak kullanılabilir olacağı anlamına gelir.

Kurucular

Yapıcı işlevlerinin anatomisini anlamadan prototipi anlamak imkansızdır.

Peki, özel bir yapıcı işlevi oluşturduğumuzda tam olarak ne olur? Sınıf tanımımızda sihirli bir şekilde iki özellik ortaya çıkıyor: constructor ve prototype.constructor.

Aynı nesneyi göstermiyorlar. Onları parçalayalım:

Diyelim ki yeni bir sınıf Vinç tanımladık (işlev veya sınıf anahtar kelimesini kullanarak).

Yeni yarattığımız özel bir kurucu şimdi özel Crane sınıfımızın prototip özelliğine eklenmiştir. Kendi yapıcısına işaret eden bir bağlantı. Dairesel mantık yaratır. Ama bu yapbozun sadece bir parçası.

Şimdi Crane.constructor'a bir göz atalım:

Crane.constructor, yaratıldığı nesnenin türüne işaret eder.
Tüm nesne yapıcıları doğal olarak işlev gördüğü için, Crane.constructor nesnesi işaret eder, İşlev türünde bir nesnedir, başka bir deyişle işlev yapıcısıdır.

Crane.prototype.constructor ve Crane.constructor arasındaki bu dinamik, prototip mirasını moleküler düzeyde sağlayan şeydir. JavaScript kodunu yazarken bunun hakkında nadiren düşünmeniz bile gerekir. Ancak bu kesinlikle bir röportaj sorusu.

Bunu tekrar kısaca gözden geçirelim. Crane.prototype.constructor kendi yapıcısına işaret eder. Neredeyse “ben benim” demeye benziyor.

Class anahtar sözcüğünü kullanarak bir sınıf tanımladığınızda da aynı şey olur:

Ancak, Crane.constructor özelliği, İşlev yapıcısına işaret eder.

Ve bağlantı bu şekilde kurulur.

Şimdi Crane nesnesinin kendisi başka bir nesnenin “prototipi” olabilir. Ve bu nesne başka bir nesnenin prototipi olabilir. Ve bunun gibi. Zincir sonsuza dek devam edebilir.

Yan Not: ES5 tarzı fonksiyonlar için, fonksiyonun kendisi
Yapıcı. Ancak ES6 sınıfı anahtar sözcüğü, yapıcıyı kapsamı içine yerleştirir. Bu sadece sözdizimsel bir farktır.

Prototip Tabanlı Miras

Her zaman sınıfı kullanmalı ve nesneleri oluşturmak ve miras almak için anahtar kelimeleri genişletmeliyiz. Ama onlar sadece perde arkasında gerçekte olanlar için bir şeker ambalajıdır.

ES5 stili sözdizimini kullanarak nesne devralma hiyerarşileri oluşturmakla birlikte, uzun zaman önce modası geçmiş ve profesyonel yazılım geliştiricileri arasında nadiren görülüyor olsa da, anladığınızda gerçekte nasıl çalıştığını daha iyi anlayacaksınız.

Yeni bir nesne tanımlayalım ve 3 özellik ekleyelim: tür, renk ve yumurta. Ayrıca 3 yöntem ekleyelim: fly, walk ve lay_egg. Bütün kuşların yapabileceği bir şey:

Kasten lay_egg yöntemini seçtiğime dikkat edin. Hatırla nasıl
daha önce tartışılan Bird.protopepe kendi kurucusuna mı işaret ediyor?

Alternatif olarak yumurta yumurtası yöntemini, bir sonraki örnekte gösterildiği gibi doğrudan Bird.prototype'e eklemiş olabilirsiniz:

İlk bakışta, bu anahtar kelimeyi Kuş içinde kullanarak ve basitçe doğrudan Bird.prototype özelliğine ekleme yöntemleri arasında ekleme yöntemleri arasında bir fark yok gibi görünebilir. Çünkü hala doğru çalışıyor mu?

Ancak bu tamamen doğru değil. Henüz ayrıntılara girmeyeceğim, çünkü buradaki ayrımı tam olarak anlamadım. Ancak konuyla ilgili daha fazla bilgi topladığımda bu öğreticiyi güncellemeyi planlıyorum.

(prototip gazilerinden yorumlarınızı bekliyoruz!)

Tüm Kuşlar Benzer Olmaz

Nesne mirasının tüm amacı, o sınıfın tüm çocuklarının otomatik olarak miras alacağı tüm özellikleri ve yöntemleri tanımlayan ortak bir sınıf kullanmaktır. Bu kodu kısaltır ve hafızayı korur.

(Tekrar tekrar tüm alt nesneler üzerinde aynı özellik ve yöntemleri tanımladığınızı hayal edin. İki kat daha fazla hafıza alacaktır.)

Birkaç farklı kuş türü yaratalım. Hepsi hala uçabiliyor olsalar bile, walk ve lay_eggs (ana Kuş sınıfından miras aldıkları için) her benzersiz kuş türü, bu sınıfa özgü kendi yöntemlerini ekleyecektir. Örneğin, yalnızca papağanlar konuşabilir. Ve sadece kuzgunlar bulmacaları çözebilir. Sadece bir songbird şarkı söyleyebilir.

Papağan
Bir Papağan yaratalım ve onu Kuştan miras alalım:

Papağan, tıpkı Kuş gibi düzenli bir yapıcı işlevdir.

Aradaki fark, Bird’ün Bird.call ile kurucusunu çağırmamız ve kendi yöntemlerimizi eklemeden önce Parrot’un bu bağlamını geçmemiz. Bird.call tüm özelliklerini ve yöntemlerini Parrot'a ekler. Buna ek olarak, kendi yöntemimizi de ekliyoruz: talk.

Şimdi papağanlar uçabiliyor, yürüyebiliyor, yumurtlayabiliyor ve konuşabiliyor! Fakat Parrot'un içinde uçma yürüyüşü ve lay_eggs metotlarını tanımlamamız gerekmedi.

kuzgun
Aynı şekilde, Raven'i yaratalım ve onu Bird'den miras alalım:

Kuzgunlar bilmeceleri çözebilecekleri için benzersizdir.

ötücü kuş
Şimdi Songbird'ü oluşturalım ve onu Bird'den devralalım:

Ötücü kuşlar şarkı söyleyebilir.

Kuşları Test Etme

Az önce eşsiz yeteneklere sahip bir sürü kuş yarattık. Ne görelim
Onlar yetenekli! Şimdiye kadar sadece sınıfları tanımladık ve
hiyerarşik ilişki.

Nesnelerle çalışmak için onları başlatmamız gerekiyor:

Orijinal Bird yapıcısını kullanarak bir serçeyi başlatalım:

Serçe uçabiliyor, yürüyebiliyor ve yumurtlayabiliyor, çünkü bütün bu yöntemleri tanımlayan Kuş'tan devralınmıştı.

Fakat bir serçe konuşamaz. Çünkü bu bir Papağan değil.

Parrot sınıfından bir muhabbet kuşu yaratalım:

Papağan Kuş'tan miras kaldığından, tüm yöntemlerini elde ederiz. Bir muhabbet kuşunun konuşma yeteneği eşsizdir, ancak şarkı söyleyemez! Sing yöntemi yalnızca Songbird türündeki nesnelerde bulunur. Songbird sınıfından starling miras alalım:

Son olarak, bir kuzgun yaratalım ve bazı bulmacaları çözelim:

Sınıf kullanmak ve anahtar kelimeleri genişletmek

ES5 tarzı yapıcılar biraz hantal olabilir.

Neyse ki şimdi sınıfımız var ve bir önceki bölümde yaptığımızın aynısını gerçekleştirmek için anahtar kelimeleri genişletiyoruz.

sınıf işlevi değiştirir

extends ve super () önceki örneklerden Bird.call'ı değiştirir.

Not Ana sınıfın yapıcısını çağıran super () kullanmalıyız.

Bu sözdizimi daha yönetilebilir görünüyor!

Şimdi tek yapmamız gereken nesneyi başlatmak:

genel bakış

Sınıf kalıtımı, nesnelerin hiyerarşisini oluşturmaya yardımcı olur.

Sınıflar, uygulama tasarımınızın ve mimarinizin temel yapı taşlarıdır. Kodla çalışmayı biraz daha insan yapar.

Tabii ki, Kuş sadece bir örnekti. Gerçek dünyadaki bir senaryoda, ne tür bir uygulama oluşturmaya çalıştığınıza bağlı olarak herhangi bir şey olabilir.

Araç sınıfı, Motosiklet, Otomobil veya Tank ebeveyni olabilir.

Balık, Shark, Goldfish, Pike ve benzeri ürünleri devralmak için kullanılabilir.

Kalıtım, daha temiz kod yazmamıza ve ana nesneyi, yinelenen nesne özelliği ve yöntem tanımlarında hafızadan tasarruf etmemize yardımcı olur.