__Proto__'un constructor.prototype'den farkı nedir?


163
function Gadget(name, color)
{
   this.name = name;
   this.color = color;
}

Gadget.prototype.rating = 3

var newtoy = new Gadget("webcam", "black")

newtoy.constructor.prototype.constructor.prototype.constructor.prototype 

Nesneyi her zaman rating = 3 ile döndürür.

Ama eğer aşağıdakileri yaparsam:

newtoy.__proto__.__proto__.__proto__

Zincir geri dönüyor null.

Ayrıca Internet Explorer'da bir __proto__özellik yoksa null değerini nasıl kontrol ederim ?


30
Bu grafik diyagram , prototip ve proto arasındaki farkı anlamanıza yardımcı olacaktır . Sen takip edebilirsiniz proto newtoy nesneden zincir ve sonra neden 3 gerçekleştirecek Proto Newtoy gelen boş.
bit

Ayrıca şemadan newtoy.prototypeeşit olmayan newtoy.constructor.prototypeve bu nedenle newtoy.constructor.prototypeçağrılan özelliğe sahip olmayacak şekilde açıktır rating. Benzer şekilde newtoy.constructor.prototype.constructor.property, çağrılan mülk de olmayacaktır rating.
bit

Son yorumda yazım hatası: bu nedenle newtoy.constructor.prototypederecelendirme adı verilen bir özelliğe sahip olacaktır. Benzer şekilde newtoy.constructor.prototype.constructor.propertyderecelendirme adı verilen bir özelliğe de sahip olacaktır.
bit


1
@Royi Namir github üzerine jsViz yükledim . İşte demo sitesi . Lütfen gerçek kodun ne kadar bakımsız (ve kirli) olduğunu unutmayın. Sonsuza kadar temas etmediğim süper eski projesi.
bitleri

Yanıtlar:


210

Ben son zamanlarda başımı bu etrafında sarmaya çalışıyorum ve nihayet bu "harita" ile geldi düşünüyorum bence konu üzerinde tam ışık

http://i.stack.imgur.com/KFzI3.png resim açıklamasını buraya girin

Bunu telafi eden ilk kişi olmadığımı biliyorum ama onu bulmaktan daha ilginçti :-). Her neyse, bundan sonra, örneğin, temelde aynı olduğunu düşündüğüm başka bir diyagramı buldum:

Javascript nesne düzeni

Benim için en şaşırtıcı şey , bunun yerine şunu Object.__proto__işaret etmekti , ama eminim bunun için iyi bir neden var :-)Function.prototypeObject.prototype

Herkesin test etmek istediği için burada resimde belirtilen kodu da yapıştırıyorum. Bazı atlamalardan sonra nerede olduğumuzu bilmemizi kolaylaştırmak için bazı özelliklerin nesnelere eklendiğini unutmayın:

Object.O1='';
Object.prototype.Op1='';

Function.F1 = '';
Function.prototype.Fp1 = '';

Cat = function(){};
Cat.C1 = '';
Cat.prototype.Cp1 = '';

mycat = new Cat();
o = {};

// EDITED: using console.dir now instead of console.log
console.dir(mycat);
console.dir(o);

2
@utsaina Çok güzel. OP'nin gönderdiği kodun başka bir grafik sunumunu kontrol edin. Bence diyagramlarımız teknik detaylar konusunda hemfikir.
bitleri

43
Sebebi Object.__proto__işaret ettiği Function.prototypeçünkü Object()kendisi tarafından boş bir nesnesini başlatır yerli fonksiyonudur. Bu nedenle, Object()bir işlevdir. Diğer tüm ana yerel türlerin __proto__özelliklerinin işaret ettiğini göreceksiniz Function.prototype. Object, Function, String, Number, Ve ArrayFonksiyon prototipi devralır tüm.
döner

@ drodsou 2. bağlantınız harika. Şimdi kontrol edin lütfen;) mollypages.org/misc/js.mp Güzel açıklama: D
abhisekp

@Swivel "Bu nedenle, Object () bir işlevdir" - Object'in bir işlev olduğunu mu demek istediniz? olmadan ()
giorgim

2
@GiorgiMoniava Doğru. Objectkendisi bir işlevdir; çağrılabilir Objectyürütmenin sonucu (örneğin, koşunun dönüş değeri Object()) bir işlev değildir.
Döner

67

constructor, bir prototypeişlev nesnesinin özelliğiyle gösterilen nesnenin önceden tanımlanmış [[DontEnum]] özelliğidir ve başlangıçta işlev nesnesinin kendisine işaret eder.

__proto__ bir nesnenin dahili [[Prototip]] özelliğine, yani gerçek prototipine eşdeğerdir.

İle bir nesne oluşturduğunuzda newİşleç , onun dahili [[Prototip]] özelliği yapıcı işlevinin prototypeözelliği tarafından işaret edilen nesneye ayarlanır .

Bu araçlar .constructoriçin değerlendirecek .__proto__.constructor, yani nesne oluşturmak için kullanılan yapıcı işlevini ve biz öğrendik olarak,protoype bu işlevin özelliği nesnenin [[Prototip]] 'i ayarlamak için kullanılmıştır.

Bu izler .constructor.prototype.constructorile aynıdır .constructor(sürece bu özellikler üzerine yazılmış değil gibi); buraya bakındaha ayrıntılı bir açıklama için .

Varsa __proto__, nesnenin gerçek prototip zincirinde yürüyebilirsiniz. Düz ECMAScript3'te bunu yapmanın bir yolu yoktur, çünkü JavaScript derin miras hiyerarşileri için tasarlanmamıştır.


3
Bu 'burada' bağlantısı altın standarttır. Tam açıklamayı istiyorsanız oraya gidin.
Ricalsin

.constructor.prototypeZincirleme ile güzel yakalamak . .constructorEşit olduğunu görmedim ama benim için de belirsizdim .__proto__.constructor. Bu da basitçe yapıcı işlevi ile prototipi arasında geçiş yapmak demektir.
Johnny_D

30

JavaScript'teki Prototypal Devralma __proto__, her nesnenin kendi __proto__özelliği tarafından başvurulan nesnenin içeriğini devralması anlamında özelliğe dayanır .

prototypeMülkiyet yalnızca özeldir Functionnesneler ve sadece kullanırken newbir çağrı operatörün Functionyapıcı olarak. Bu durumda, oluşturulan nesneler __proto__yapıcılara ayarlanır Function.prototype.

Bu, ekleme işleminin Function.prototypeotomatik __proto__olarak referans veren tüm nesnelere yansıyacağı anlamına gelir .Function.prototype .

Yapıcı en Değiştirme Function.prototypebaşka bir nesneyle olacak değil güncelleme__proto__ zaten varolan nesnelerin herhangi mülkü.

Not, __proto__özelliği doğrudan erişilemez olmalıdır, Object.getPrototypeOf (nesne) yerine kullanılır.

İlk soruyu cevaplamak için, ısmarlama bir şema __proto__ve prototypereferanslar oluşturdum, maalesef stackoverflow "10'dan az itibar" ile resim eklememe izin vermiyor. Belki başka bir zaman.

[Düzenle] Şekil [[Prototype]]bunun yerine kullanır __proto__çünkü ECMAScript belirtimi dahili nesnelere bu şekilde başvurur. Umarım her şeyi çözebilirsin.

Rakamı anlamanıza yardımcı olacak bazı ipuçları:

red    = JavaScript Function constructor and its prototype
violet = JavaScript Object constructor and its prototype
green  = user-created objects
         (first created using Object constructor or object literal {},
          second using user-defined constructor function)
blue   = user-defined function and its prototype
         (when you create a function, two objects are created in memory:
          the function and its prototype)

O Not constructormülkiyet oluşturulan nesnelere mevcut değildir, ancak prototip miras alınır.

resim açıklamasını buraya girin


@xorcus bunu açıklayabilir misiniz: new MyFunction()onun bir nesne örneğini oluşturur __proto__edilir onun ctor prototip başvurmalıdır MyFunction.prototype.Peki neden yapar MyFunction.prototype.__proto__hiç referes Object.prototype? (benim ilk örneğim gibi) onun datoresinin prototipine gönderme yapmalıdır (bir instnace MyFunction.prototypeolduğuna dikkat edin )MyFunction.prototypeMyfunction
Royi Namir

@Royi Namir: MyFunction.prototype .__ proto__, Object.prototype değiniyor çünkü MyFunction.prototype bir nesne. Object.prototype tüm nesneler tarafından miras alınır (normalde, prototip miras zinciri burada biter). MyFunction.prototype uygulamasının MyFunction'ın bir örneği olduğunu kabul etmiyorum. obj instanceof MyFunction <=> MyFunction.prototype.isPrototypeOf (obj) <=> MyFunction.prototype, obj prototip zincirinde bulunur. MyFunction.prototype nesnesi için durum böyle değil
xorcus

14

ObjectHavva ve FunctionAdem, Adem (olan Function) kemiğini (kullanır Function.prototypeHavva'yı yaratmak için) ( Object). Sonra Adam'ı ( Function) kim yarattı ? - JavaScript dilinin mucidi :-).

Utsaina'nın cevabına göre, daha yararlı bilgiler eklemek istiyorum.

Benim için en şaşırtıcı şey, Object.__proto__Function.prototype , bunun yerine şunu işaretObject.prototype , ama eminim bunun için iyi bir neden var :-)

Olmamalı. Object.__proto__işaret ETMEMELİDİRObject.prototype . Bunun yerine, örneği Object o, o.__proto__işaret etmelidir Object.prototype.

(Şartları classve instanceJavaScript'i kullandığım için beni affet , ama biliyorsun :-)

Sınıfın Objectkendisinin bir örneği olduğunu düşünüyorum Function, bu yüzden Object.__proto__ === Function.prototype. Bu nedenle: ObjectHavva ve FunctionAdam, Adam ( Function) kemiğini ( Function.prototype) Havva ( Object) ' yı yaratmak için kullanır .

Dahası, hatta sınıf Functionkendisinin bir örneğidir Functionolduğunu kendisi, Function.__proto__ === Function.prototypeo da bu yüzden,Function === Function.constructor

Ayrıca, normal sınıf Catbir örneğidir Function, yani Cat.__proto__ === Function.prototype.

Yukarıdakilerin nedeni, JavaScript'te bir sınıf oluşturduğumuzda, aslında sadece bir örnek olması gereken bir işlev oluşturuyoruz Function. Objectve Functionsadece özeldir, ama bunlar hala sınıftır, Catnormal sınıftır.

Faktör olarak, Google Chrome JavaScript motorunda aşağıdaki 4:

  • Function.prototype
  • Function.__proto__
  • Object.__proto__
  • Cat.__proto__

Hepsi ===diğer 3'e (kesinlikle eşit) ve değerlerifunction Empty() {}

> Function.prototype
  function Empty() {}
> Function.__proto__
  function Empty() {}
> Object.__proto__
  function Empty() {}
> Cat.__proto__
  function Empty() {}
> Function.prototype === Function.__proto__
  true
> Function.__proto__ === Object.__proto__
  true
> Object.__proto__ === Cat.__proto__
  true

TAMAM. Sonra özelfunction Empty() {} ( Function.prototype) 'i ? Bunu düşün :-)


Bunu kabul edin, son bir şey hariç: function Empty() {}Function.prototype, etc'ye eşit olmaktan ne kastediyorsunuz? Chrome konsolunda kullandığınız kod nedir?
drodsou

2
Belirttiğiniz son şeyi düzelttim. Değerleri function Empty() {}Google Chrome'da. Konsol çıkışını da ekledim.
Peter Lee

tüm işlevler Function örneğidir ve bu nedenle tüm işlevler _ _proto_ _Function.prototype öğesinden devralınır ( ). Bu kadar basit :)
xorcus

Eski konu hakkında yorum yaptığım için üzgünüm. Peki Dilin Mucidi tarafından mı yaratılıyorlar?
Patel Parth

6

İnsanların sizi anlayışınızdaki asıl sorunun nerede düzeltmediğini gerçekten bilmiyorum.

Bu, sorunu tespit etmenizi çok daha kolay hale getirir

Şimdi neler olduğunu görelim:

var newtoy = new Gadget("webcam", "black")

newtoy 
  .constructor //newtoy's constructor function is newtoy ( the function itself)
    .prototype // the function has a prototype property.( all functions has)
      .constructor // constructor here is a **property** (why ? becuase you just did `prototype.constructor`... see the dot ? )  ! it is not(!) the constructor function  !!! this is where your mess begins. it points back to the constructor function itself ( newtoy function)
         .prototype // so again we are at line 3 of this code snippet
            .constructor //same as line 4 ...
                .prototype 
                 rating = 3

Harika, şimdi buna bakalım __proto__

Bundan önce, lütfen aşağıdakilerle ilgili 2 şeyi unutmayın __proto__ :

  1. newİşleç ile bir nesne oluşturduğunuzda , internal [[Prototype]]/ proto__özelliği isterseniz veya "yaratıcısı" prototypeözelliğine (1) ayarlanır constructor function.

  2. Sert JS içinde kodlanmış -: Object.prototype.__proto__olduğunu null.

Bu 2 noktaya " bill"

newtoy
     .__proto__ // When `newtoy` was created , Js put __proto__'s value equal to the value of the cunstructor's prototype value. which is `Gadget.prototype`.
       .__proto__ // Ok so now our starting point is `Gadget.prototype`. so  regarding "bill" who is the constructor function now? watch out !! it's a simple object ! a regular object ! prototype is a regular object!! so who is the constructor function of that object ? Right , it's the `function Object(){...}`.  Ok .( continuing "bill" ) does it has a `prototype` property ? sure. all function has. it's `Object.prototype`. just remember that when Gadget.prototype was created , it's internal `__proto__` was refered to `Object.prototype` becuase as "bill" says :"..will be set to the `prototype` property of   its `constructor function`"
          .__proto__ // Ok so now our satrting point is `Object.prototype`. STOP. read bullet 2.Object.prototype.__proto__ is null by definition. when Object.prototype ( as an object) was created , they SET THE __PROTO__ AS NULL HARDCODED

Daha iyi?


2

Her fonksiyon kendi prototipini yaratır. Bu işlev yapıcısını kullanarak bir nesne oluşturduğumuzda, nesnemin __proto__ özelliği bu işlevin prototipini işaret etmeye başlayacaktır.


1
__proto__Mülkiyet demek istedim .
demisx

Evet. Bir nesnenin proto özelliği demek istedim . Umarım bilgiler faydalı olmuştur.
Apoorv Nag

2

Tüm bu rakamlar ezici olsaydı, özelliklerin ne anlama geldiğine bir göz atalım.

STH.prototype

Yeni bir işlev oluştururken paralel olarak yaratılan ve işleve [[Prototype]]zincirle bağlanan boş bir nesne vardır . Bu nesneye erişmek prototypeiçin işlevin özelliğini kullanırız .

function Gadget() {}
// in background, new object has been created
// we can access it with Gadget.prototype
// it looks somewhat like {constructor: Gadget}

prototypeÖzelliğin yalnızca işlevler için kullanılabileceğini unutmayın .

STH.constructor

Yukarıda belirtilen prototip nesnesinin bir - dışında hiçbir özelliği yoktur constructor. Bu özellik, prototip nesnesini oluşturan bir işlevi temsil eder.

var toy = new Gadget();

Fonksiyon oluştururken Gadget, biz {constructor: Gadget}de buna benzer bir nesne yarattık Gadget.prototype. Olarak constructorbir amacı, prototip hazırlandı bir fonksiyonu belirtir, toy.constructortemsil Gadgetişlevi. Yazıyoruz toy.constructor.prototypeve {constructor: Gadget}tekrar başlıyoruz .

Bu nedenle, bir kısır döngü var: kullanabilirsiniz toy.constructor.prototype.constructor.prototype.constructor.prototype.constructor.prototype.constructor.prototype.constructor.prototype.constructor.prototype.constructor.prototypeve her zaman olacaktır Gadget.prototype.

toy
.constructor    // Gadget
.prototype    // {constructor: Gadget}
.constructor    // Gadget
.prototype    // {constructor: Gadget}
// ...

STH .__ proto__

prototypeİşlevlere özgü bir özellik olsa da, __proto__tüm nesneler için olduğu gibi kullanılabilir Object.prototype. Bir nesne oluşturabilen bir fonksiyonun prototipini ifade eder.

[].__proto__ === Array.prototype
// true

({}).__proto === Object.prototype
// true

İşte, toy.__proto__öyle Gadget.prototype. Olarak Gadget.prototypebir amacı, (bir {}) ve nesneler ile oluşturulur Object(yukarıdaki örnekteki gibi) işlev elde ederiz Object.prototype. Bu, JavaScript'teki daha yüksek nesnedir ve __proto__yalnızca gösterebilir null.

toy
.__proto__    // Gadget.prototype (object looking like {constructor: Gadget})
.__proto__    // Object.prototype (topmost object in JS)
.__proto__    // null - Object.prototype is the end of any chain

0

Kısa cevap: nesneyi oluşturan yapıcı özelliğine __proto__bir referanstır prototype.

JavaScript'teki nesneler

JavaScript nesnesi, sıfır veya daha fazla özellik koleksiyonu için yerleşik bir türdür . Özellikler, diğer nesneleri, ilkel değerleri veya işlevleri tutan kaplardır.

JavaScript'teki yapıcılar

Fonksiyonlar (uygulamak düzenli nesnelerdir [[Call]]çağrılabilir olmanın ek özelliği ile ECMA-262 açısından) fakat JavaScript başka bir rol oynar: onlar kurucular (haline fabrikalar aracılığıyla çağrılan eğer nesneler için)new operatör . Böylece yapıcılar diğer dillerdeki sınıflara kaba bir analogudur.

Her JavaScript işlevi aslında prototip tabanlı miras ve paylaşılan özellikleri uygulamak için kullanılan Functionadlı özel bir özelliğe sahip yerleşik işlev nesnesinin bir örneğidir prototype. Bir yapıcı işlevi tarafından oluşturulan her nesnenin, yapıcısının değerine örtülü bir referansı (prototip veya denir __proto__) vardır prototype.

Yapıcı prototypebir çeşit planı yapıcısı tarafından oluşturulan her nesne bir başvuru devralır beri nesneleri oluşturmak için onunprototype .

Prototip zinciri

Bir nesne prototipini internal özelliği [[Prototype]]veya yoluyla belirtir __proto__. İki nesne arasındaki prototip ilişkisi kalıtımla ilgilidir: her nesnenin prototipi olarak başka bir nesnesi olabilir. Prototip nulldeğer olabilir .

__proto__Özellik tarafından bağlanan nesne zincirine prototip zinciri denir . Bir nesnedeki bir özelliğe başvuru yapıldığında, bu başvuru, prototip zincirindeki o adın bir özelliğini içeren ilk nesnede karşılaşılan özelliğe yapılır. Prototip zinciri sanki tek bir nesne gibi davranır.

Bu resme bakın (bu blogdan alınmıştır ):

proto.jpg

Bir nesnedeki bir özelliğe erişmeye çalıştığınızda, JavaScript bu nesnede aramayı başlatır ve özellikle karşılaşılana veya __proto__değeri tutarsa, prototipiyle, prototipin prototipiyle vb. Devam eder null.

Prototip zincirini kullanan bu tür kalıtım , sınıf zincirini kullanan diğer dillerle karışıklığı önlemek için genellikle temsilci seçme olarak adlandırılır .

Hemen hemen tüm nesneler örneklerdir Object, çünkü Object.prototypeprototip zincirlerinde sonuncudur. Ama Object.prototypebunun bir örneği değildir Objectçünkü Object.prototype.__proto__değeri tutar null.

Ayrıca, aşağıdaki nullgibi bir prototipi olan bir nesne de oluşturabilirsiniz :

var dict = Object.create(null);

Böyle bir nesne, gerçek bir nesneden daha iyi bir haritadır (sözlük), bu nedenle bu desene bazen dikte deseni ( dikte) denir sözlük için ) .

Not: kullanılarak oluşturulan edebi nesneleri {}örnekleri olan Objectbu yana ({}).__proto__bir referanstır Object.prototype.


Lütfen kullandığınız alıntıların ve eserlerin kaynağını belirtin. Resim giamir.com/pseudoclasses-and-prototypal-inheritance-in-JS adresinden geliyor gibi görünüyor , üzerinde telif hakkınız var mı?
Bergi

@Bergi Görüntünün kaynağına değindim. Kullandığım tırnakların çoğu ya JS standardından ya da
MDN'den alınmıştır
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.