Javascript'in perde sahnelerini anlamaya çalışıyorum ve nesnelerin, özellikle Nesne ve Fonksiyonun yaratılmasını ve aralarındaki ilişkiyi anlamaya sıkıştım.
Bu karmaşık, yanlış anlaşılması kolaydır ve birçok yeni başlayan Javascript kitabı yanlış anlıyor, bu yüzden okuduğunuz her şeye güvenmeyin.
1990'larda ve standardizasyon komitesinde Microsoft'un JS motorunun uygulayıcılarından biriydim ve bu yanıtı bir araya getirirken bir takım hatalar yaptım. (15 yılı aşkın süredir bu konuda çalışmadığım için affedilebilirim.) Bu zor şeyler. Ama prototip mirasını anladıktan sonra, her şey mantıklı.
Array, String vb.Gibi tüm yerleşik nesnelerin Object'den uzantı (devralınan) olduğunu okuduğumda, Object'in yaratılan ilk nesne olduğunu ve kalan nesnelerin kendisinden miras aldığını varsaydım.
Derse dayalı kalıtım hakkında bildiğiniz her şeyi atın. JS, prototip tabanlı miras kullanır.
Ardından, kafanızda "kalıtım" ın ne anlama geldiğini çok açık bir şekilde tanımladığınızdan emin olun. C # veya Java veya C ++ gibi OO dillerine alışkın olan insanlar, kalıtımın alt tipleme olduğunu düşünürler, ancak miras alt tipleme anlamına gelmez. Kalıtım, bir şeyin üyelerinin de başka bir şeyin üyeleri olduğu anlamına gelir . O değil mutlaka bu şeyler arasında bir alt-tiplemesi ilişki olduğunu demek! Tür teorisindeki pek çok yanlış anlama, insanların bir fark olduğunu fark etmemelerinin sonucudur.
Ancak, Nesnelerin yalnızca işlevler tarafından oluşturulabileceğini bilmeniz mantıklı değildir, ancak işlevler de İşlev nesnelerinden başka bir şey değildir.
Bu sadece yanlış. Bazı nesneler vardır değil arayarak yarattığı new F
bazı fonksiyon için F
. Bazı nesneler JS çalışma zamanı tarafından hiçbir şey olmadan oluşturulur. Herhangi bir tavuk tarafından bırakılmayan yumurtalar var . Bunlar, başlangıçta çalışma zamanı tarafından oluşturuldu.
Kuralların ne olduğunu söyleyelim ve belki de bu yardımcı olacaktır.
- Her nesne örneğinin bir prototip nesnesi vardır.
- Bazı durumlarda bu prototip olabilir
null
.
- Nesne örneğindeki bir üyeye erişirseniz ve nesnede bu üye yoksa, nesne prototipini savunur veya prototip boşsa durur.
prototype
Bir nesnenin üyesi genellikle değil nesnenin prototip.
- Daha ziyade,
prototype
bir fonksiyon nesnesinin F üyesi, tarafından yaratılan nesnenin prototipi haline gelecek olan nesnedir new F()
.
- Bazı uygulamalarda, örnekler
__proto__
prototiplerini gerçekten veren bir üye alır. (Bu artık kullanımdan kaldırılmıştır. Buna güvenmeyin.)
- İşlev nesneleri
prototype
, oluşturulduklarında atanan yepyeni bir varsayılan nesneye sahip olur.
- Bir fonksiyon nesnesinin prototipi elbette
Function.prototype
.
Özetleyelim.
- Prototip
Object
DİRFunction.prototype
Object.prototype
nesne prototip nesnesidir.
- Prototip
Object.prototype
DİRnull
- Prototip
Function
DİR Function.prototype
- bu nadir durumlardan biridir Function.prototype
aslında bir prototipi Function
!
Function.prototype
işlev prototip nesnesidir.
- Prototip
Function.prototype
DİRObject.prototype
Farzedelim ki bir işlev Foo yapıyoruz.
- Prototip
Foo
DİR Function.prototype
.
Foo.prototype
Foo prototip nesnesidir.
- Prototip
Foo.prototype
DİR Object.prototype
.
Varsayalım diyelim new Foo()
- Yeni nesnenin prototipi
Foo.prototype
Bunun mantıklı olduğundan emin olun. Hadi çizelim. Ovaller nesne örnekleridir. Kenarlar ya __proto__
"prototipi" prototype
anlamına gelir ya da " prototype
özelliği " anlamına gelir .
Çalışma zamanının tek yapması gereken, tüm bu nesneleri oluşturmak ve çeşitli özelliklerini buna göre atamaktır. Eminim bunun nasıl yapılacağını görebilirsiniz.
Şimdi bilginizi test eden bir örneğe bakalım.
function Car(){ }
var honda = new Car();
print(honda instanceof Car);
print(honda.constructor == Car);
Bu ne yazdırıyor?
Ne instanceof
demek istiyorsun? honda instanceof Car
" prototip zincirindeki Car.prototype
herhangi bir nesneye eşit honda
mi?"
Evet öyle. honda
'ın prototipi Car.prototype
, yani işimiz bitti. Bu doğru yazdırır.
İkincisi ne olacak?
honda.constructor
mevcut olmadığından prototipe danışıyoruz, yani Car.prototype
. Ne zaman Car.prototype
nesne otomatik bir özellik verildi oluşturulduğu constructor
için eşit Car
bu doğrudur, bu yüzden.
Şimdi buna ne dersiniz?
var Animal = new Object();
function Reptile(){ }
Reptile.prototype = Animal;
var lizard = new Reptile();
print(lizard instanceof Reptile);
print(lizard.constructor == Reptile);
Bu program ne yazdırıyor?
Yine, lizard instanceof Reptile
" prototip zincirindeki Reptile.prototype
herhangi bir nesneye eşit lizard
mi?"
Evet öyle. lizard
'ın prototipi Reptile.prototype
, yani işimiz bitti. Bu doğru yazdırır.
Şimdi ne olacak
print(lizard.constructor == Reptile);
Bunun da lizard
inşa edildiğinden beri doğru yazdırdığını düşünebilirsiniz, new Reptile
ancak yanılıyorsunuz. Nedeni.
- Mu
lizard
bir var constructor
mülkiyet? Hayır. Bu yüzden prototipe bakıyoruz.
- Prototipi
lizard
olduğu Reptile.prototype
olan Animal
.
- Mu
Animal
bir var constructor
mülkiyet? Hayır. Bu yüzden prototipine bakıyoruz.
- Prototipi
Animal
olan Object.prototype
ve Object.prototype.constructor
çalışma zamanı tarafından oluşturulan ve eşit olduğunu Object
.
- Bu yanlış yazdırıyor.
Reptile.prototype.constructor = Reptile;
Orada bir noktada söylemeliydik , ama hatırlamıyorduk!
Her şeyin sizin için anlamlı olduğundan emin olun. Hala kafa karıştırıcıysa bazı kutular ve oklar çizin.
Diğer son derece kafa karıştırıcı olan şey, eğer console.log(Function.prototype)
bir işlev yazdırırsam, ancak console.log(Object.prototype)
yazdırdığımda bir nesne yazdırır. Neden Function.prototype
bir nesne olması gerektiği bir fonksiyon?
İşlev prototipi çağrıldığında geri dönen bir işlev olarak tanımlanır undefined
. Bunu zaten biliyoruz Function.prototype
olduğu Function
işin garibi, prototip. Bu nedenle Function.prototype()
yasaldır ve bunu yaptığınızda undefined
geri dönersiniz. Yani bu bir işlev.
Object
Prototip bu özelliği yoktur; çağrılabilir değil. Bu sadece bir nesne.
console.log(Function.prototype.constructor)
o zaman tekrar bir işlevdir.
Function.prototype.constructor
adildir Function
açıkçası. Ve Function
bir işlevdir.
Şimdi bir şeyi kendiniz yaratmak için nasıl kullanabilirsiniz (Mind = blown).
Bunu fazla düşünüyorsun . Gereken tek şey, çalışma zamanının başladığında bir grup nesne oluşturmasıdır. Nesneler, dizeleri nesnelerle ilişkilendiren arama tablolarıdır. Çalışma zamanı başladığında, o yapması gereken atama başlatmak sonra bir kaç düzine boş nesneler oluşturmak ve olan prototype
, __proto__
, constructor
ve bu yüzden yaptıkları gerektiğini grafiği yapana kadar her nesnenin özelliklerine.
Size yukarıda verdiğim şemayı alıp constructor
ona kenarlar eklemeniz yararlı olacaktır. Bunun çok basit bir nesne grafiği olduğunu ve çalışma zamanının onu oluştururken sorun yaşamayacağını hızlı bir şekilde göreceksiniz.
İyi bir egzersiz kendiniz yapmak olacaktır. İşte, ben başlayacağım. Biz kullanacağız my__proto__
anlamına "prototipi nesnesi" ve myprototype
"prototipi özelliğini" demek.
var myobjectprototype = new Object();
var myfunctionprototype = new Object();
myfunctionprototype.my__proto__ = myobjectprototype;
var myobject = new Object();
myobject.myprototype = myobjectprototype;
Ve bunun gibi. Programın geri kalanını, "gerçek" Javascript yerleşik nesneleriyle aynı topolojiye sahip bir nesne kümesi oluşturmak için doldurabilir misiniz? Bunu yaparsanız, son derece kolay olduğunu göreceksiniz.
JavaScript'teki nesneler, yalnızca dizeleri diğer nesnelerle ilişkilendiren arama tablolarıdır . Bu kadar! Burada sihir yok. Kendinizi düğümlere bağlıyorsunuz, çünkü her nesnenin bir kurucu tarafından yaratılması gerektiği gibi, aslında var olmayan kısıtlamaları hayal ediyorsunuz.
İşlevler yalnızca ek bir özelliğe sahip nesnelerdir: çağrılacak. Bu yüzden küçük simülasyon programınızı gözden geçirin ve .mycallable
her nesneye çağrılabilir olup olmadığını gösteren bir özellik ekleyin . Bu kadar basit.
Function.prototype
, bunun bir işlev olabileceği ve iç alanlara sahip olabileceği anlamına gelir . Yani hayır, prototip işlevini yapısından geçerken yürütmezsiniz. Son olarak, Javascript'i yorumlayan bir motor olduğunu unutmayın, bu nedenle Nesne ve İşlev, Javascript'ten değil, motor içinde oluşturulabilir ve özel referans gibiFunction.prototype
veObject.prototype
sadece motor tarafından özel bir şekilde yorumlanabilir.