Soru JavaScript .prototype nasıl çalışır?


Bu, dinamik programlama dillerine değil, ama ben JavaScript kodunun adil paylaşımını yazdım. Bu prototip tabanlı programlama etrafında kafamı hiç almamıştım, bunun nasıl çalıştığını bilen var mı?

var obj = new Object(); // not a functional object
obj.prototype.test = function() { alert('Hello?'); }; // this is wrong!

function MyObject() {} // a first class functional object
MyObject.prototype.test = function() { alert('OK'); } // OK

İnsanlarla bir süre önce yaptığım bir sürü tartışmayı hatırlıyorum (yaptığımdan tam olarak emin değilim) ama anladığım kadarıyla bir sınıf kavramı yok. Bu sadece bir nesne ve bu nesnelerin örnekleri orijinalin klonlarıdır, değil mi?

Ama bunun tam amacı nedir .prototype JavaScript özellikli? Nesnelerin oluşturulmasında nasıl bir ilişki vardır?


Düzenle

Bunlar slaytlar Bu konuyu anlamak için gerçekten çok yardımcı oldu.


1858
2018-02-21 12:31


Menşei


John Resig'in konuya bakarken bana yardımcı olan prototipler üzerinde birkaç kaydı vardır (kodda değişiklikler yapabilir ve neler olduğunu görebilirsiniz ...) http://ejohn.org/apps/learn/#64 - John Foster
Büyük referans materyal, bu soruyu bilgilendirici bir şekilde saklamak için belki de sitenizin linkinizin artık mevcut olmadığı bir şekilde değişmesi durumunda, John'un sitesinden gelen bazı yorumları cevabınıza yerleştirir. Her iki yol da bana yardımcı oldu. - Chris
Bağlantınız için +1 John Resig'in JavaScript Ninja slaydı # 64. Oradan başlayarak gerçekten yardımcı oldu ve prototipleri doğru anladığımı hissediyorum. - a paid nerd
Prototip uygulamak için gerçekten işlevsel bir cisme ihtiyacımız var mı? eğer evet nedense? - Anshul
Bu size yardımcı olabilir: webdeveasy.com/javascript-prototype - Naor


Cevaplar:


Her JavaScript nesnesinde dahili bir özellik var [[Prototip]]. Bir mülkün üzerinden bakarsanız obj.propName veya obj['propName'] ve nesnenin böyle bir özelliği yoktur; obj.hasOwnProperty('propName') - çalışma zamanı, özelliği [[Prototype]] tarafından başvurulan nesnede arar. Prototip nesnesinde böyle bir özellik yoksa, prototip sırayla kontrol edilir, böylece orijinal nesnenin Prototip zinciri bir eşleşme bulunana veya sonuna ulaşılana kadar.

Bazı JavaScript uygulamaları, [[Prototype]] özelliğine doğrudan erişim sağlar, örn. __proto__. Genel olarak, sadece nesne oluşturma sırasında bir nesnenin prototipini ayarlamak mümkündür: Eğer yeni bir nesne üzerinden new Func(), nesnenin [[Prototype]] özelliği, başvurulan nesneye ayarlanacaktır. Func.prototype.

Bu, JavaScript'in kalıtım sistemini, prototipik olan ve sınıf temelli değil de, görebildiğimiz gibi, JavaScript'te simüle etmeyi sağlar:

Sadece kurucu işlevlerini sınıflar olarak ve prototipin özelliklerini (yani yapıcı işlevinin referans aldığı nesnenin) düşünün. prototype özellik olarak paylaşılan üyeler, yani her bir örnek için aynı olan üyeler. Sınıf tabanlı sistemlerde, yöntemler her bir örnek için aynı şekilde uygulanır, böylece yöntemler normal olarak prototipe eklenir, buna karşın bir nesnenin alanları örneklere özgüdür ve bu nedenle, yapım sırasında nesnenin kendisine eklenir.


927
2018-02-21 13:33



Yani, kısa snippet'imde prototip özellikteki yeni özellikleri tanımlayarak yanlış bir şey yapıyorum? - John Leidegren
Birinci sınıf vatandaş olarak işlev nesnelerine sahip olmanın bu olduğunu düşünüyorum. - John Leidegren
Özellikle programlama dillerinde standart olmayan şeylerden nefret ediyorum, neden var ki proto Açıkça gerekli olmadığında? - John Leidegren
@ H1D: eğer Class.method bulunamadı, çalışma zamanı Class.__proto__.method (ya da daha doğrusu Object.getPrototypeOf(Class).method uyumlu ES5) ve değil  Class.prototype.method - Christoph
kullanımı not [[Prototip]] kasıtlı - ECMA-262, çifte köşeli parantez ile dahili özelliklerin isimlerini içerir - Christoph


Java, C # veya C ++ gibi klasik mirasları uygulayan bir dilde, bir sınıf oluşturarak başlarsınız - nesneleriniz için bir plan - ve o zaman bu sınıftan yeni nesneler yaratabilir ya da sınıfı genişleterek yeni bir sınıf oluşturur. orijinal sınıf.

JavaScript'te ilk önce bir nesne yaratırsınız (sınıf kavramı yoktur), sonra kendi nesnesini artırabilir veya ondan yeni nesneler yaratabilirsiniz. Bu zor değil, ama biraz yabancı ve klasik şekilde kullanılan biri için metabolize etmek zor.

Örnek:

//Define a functional object to hold persons in JavaScript
var Person = function(name) {
  this.name = name;
};

//Add dynamically to the already defined object a new getter
Person.prototype.getName = function() {
  return this.name;
};

//Create a new object of type Person
var john = new Person("John");

//Try the getter
alert(john.getName());

//If now I modify person, also John gets the updates
Person.prototype.sayMyName = function() {
  alert('Hello, my name is ' + this.getName());
};

//Call the new method on john
john.sayMyName();

Şimdiye kadar, temel nesneyi genişletiyorum, şimdi başka bir nesne yaratıyorum ve sonra Kişi'den miras aldım.

//Create a new object of type Customer by defining its constructor. It's not 
//related to Person for now.
var Customer = function(name) {
    this.name = name;
};

//Now I link the objects and to do so, we link the prototype of Customer to 
//a new instance of Person. The prototype is the base that will be used to 
//construct all new instances and also, will modify dynamically all already 
//constructed objects because in JavaScript objects retain a pointer to the 
//prototype
Customer.prototype = new Person();     

//Now I can call the methods of Person on the Customer, let's try, first 
//I need to create a Customer.
var myCustomer = new Customer('Dream Inc.');
myCustomer.sayMyName();

//If I add new methods to Person, they will be added to Customer, but if I
//add new methods to Customer they won't be added to Person. Example:
Customer.prototype.setAmountDue = function(amountDue) {
    this.amountDue = amountDue;
};
Customer.prototype.getAmountDue = function() {
    return this.amountDue;
};

//Let's try:       
myCustomer.setAmountDue(2000);
alert(myCustomer.getAmountDue());

var Person = function (name) {
    this.name = name;
};
Person.prototype.getName = function () {
    return this.name;
};
var john = new Person("John");
alert(john.getName());
Person.prototype.sayMyName = function () {
    alert('Hello, my name is ' + this.getName());
};
john.sayMyName();
var Customer = function (name) {
    this.name = name;
};
Customer.prototype = new Person();

var myCustomer = new Customer('Dream Inc.');
myCustomer.sayMyName();
Customer.prototype.setAmountDue = function (amountDue) {
    this.amountDue = amountDue;
};
Customer.prototype.getAmountDue = function () {
    return this.amountDue;
};
myCustomer.setAmountDue(2000);
alert(myCustomer.getAmountDue());

Dediğim gibi setAmountDue (), bir kişiye GetAmountDue () diyemiyorum.

//The following statement generates an error.
john.setAmountDue(1000);

1755
2018-01-24 03:42



Bence stackoverflow üzerindeki cevaplar sadece orijinal poster için değil, aynı zamanda arama yapan diğer insanlardan oluşan büyük bir topluluğa da ilgi duyuyor. Ve onlardan biri oldum ve eski yayınlardan yararlandım. Bazı kod örneklerini ekleyerek diğer cevaplara katkıda bulunabileceğimi düşünüyorum. Sorunuz hakkında: Eğer yeni çıkmazsan işe yaramıyor. myCustomer.sayMyName () öğesini çağırdığımda "myCustomer.sayMyName bir işlev değil" i döndürür. En kolay yol, ateş böceği ile denemeler yapmak ve ne olduğunu görmek. - stivlo
Anladığım kadarıyla var Kişi = fonksiyon (isim) {...}; Kişi Nesneleri oluşturabilen bir yapıcı işlevi tanımlamaktır. Bu yüzden henüz bir Nesne yok, sadece anonim kurucu fonksiyonu Kişiye atandı. Bu çok iyi bir açıklama: helephant.com/2008/08/how-javascript-objects-work - stivlo
UYARI: Bu cevap, ana sınıf kurucusunun her bir örnek temelinde çağrılmadığını göz ardı eder. Çalışmanın tek nedeni, hem çocuğun hem de ebeveyn yapıcının aynısının (ismin ayarlanması) aynısını yapmasıdır. JavaScript'te (ve son bir çözümde) kalıtım girişimi sırasında yapılan yaygın hatalar hakkında daha ayrıntılı bir açıklama için lütfen bkz: bu yığın taşma sonrası - Aaren Cordova
Bu cevabın, "yeni Kişi ()" yi prototip olarak kullanarak, "Müşteri" nin "özellik" özelliğinin "isim" sırasını "Müşteri" olarak ayarladığınızı da belirtmedim (böylece tüm Müşteri Örnekler aynı mülke sahip olacaktır. Bu iyi bir temel örnek olsa da, YAPMAYIN. :) "Person.prototype" için prototipini ayarlayarak bir "köprü" olarak hareket etmek için yeni bir anonim işlev oluşturun, daha sonra bir örnek oluşturun ve bunun yerine "Customer.prototype" öğesini bu anonim örneğe ayarlayın. - James Wilkins
Hakkında Customer.prototype = new Person(); satır, MDN kullanarak bir örnek gösterir Customer.prototype = Object.create(Person.prototype)ve bunu belirtir 'Burada yaygın bir hata kullanmak' yeni kişi () ''. kaynak - Rafael Eyng


Bir JavaScript öğretmeni olarak rol oynuyorum ve prototip konsepti öğrettiğim zaman her zaman tartışmalı bir konu olmuştur. Konsepti aydınlatmak için iyi bir yöntem bulmak bana biraz zaman aldı ve şimdi bu metinde JavaScript .prototype nasıl çalıştığını açıklamaya çalışacağım.


Bu, henüz yorumda bulunulmayan, açıklama sırasında bir örnek olarak düşünülebilecek çok basit bir prototip tabanlı nesne modelidir:

function Person(name){
    this.name = name;
}
Person.prototype.getName = function(){
    console.log(this.name);
}
var person = new Person("George");

Prototip konseptinden önce düşünmemiz gereken bazı önemli noktalar var.

1- JavaScript işlevleri aslında nasıl çalışır?

İlk adımı atmamız için, JavaScript işlevlerinin gerçekte nasıl çalıştığını, işlev gibi bir sınıf olarak nasıl çalıştığını this İçinde anahtar kelime veya argümanlar, ne yaptığı ve ne ile döndüğü düzenli bir işlev olarak.

Diyelim ki bir Person nesne modeli. ama bu adımda olmaya çalışacağım kullanmadan aynı şeyi yap prototype ve new anahtar kelime.

Yani bu adımda functions, objects ve this anahtar kelime, sahip olduğumuz tek şey.

İlk soru olurdu Nasıl this anahtar kelime kullanmadan kullanışlı olabilir new anahtar kelime.

Bu yüzden cevaplayalım ki boş bir cisim var, ve iki fonksiyon:

var person = {};
function Person(name){  this.name = name;  }

function getName(){
    console.log(this.name);
}

ve şimdi kullanmadan new anahtar kelime Bu fonksiyonları nasıl kullanabilirdik. Yani JavaScript'in bunu yapmanın 3 farklı yolu vardır:

a. İlk yol, işlevi normal bir işlev olarak çağırmaktır:

Person("George");
getName();//would print the "George" in the console

Bu durumda, bu genellikle global olan mevcut içerik nesnesi olur. window tarayıcıdaki nesne veya GLOBAL içinde Node.js. Bu, tarayıcıda pencere.adı veya Node.js'deki GLOBAL.name değeri, "George" değeriyle sahip olduğumuz anlamına gelir.

b. Yapabiliriz iliştirmek özellikleri gibi bir nesneyi

-En kolay yol Bunu yapmak boş değiştirmek person nesne gibi:

person.Person = Person;
person.getName = getName;

Bu şekilde onları şöyle diyebiliriz:

person.Person("George");
person.getName();// -->"George"

ve şimdi person nesne gibidir:

Object {Person: function, getName: function, name: "George"}

-Bir özelliği takmanın diğer yolu bir nesneye prototype adıyla herhangi bir JavaScript nesnesinde bulabileceğiniz bu nesnenin __proto__ve özet bölümünü biraz açıklamaya çalıştım. Böylece benzer bir sonuç elde ederek elde edebiliriz:

person.__proto__.Person = Person;
person.__proto__.getName = getName;

Fakat Bu şekilde yaptığımız şey, Object.prototypeÇünkü, her zaman editörleri kullanarak bir JavaScript nesnesi oluşturuyoruz ({ ... }), dayalı oluşturulur Object.prototypeYani, yeni oluşturulan nesneye adında bir özellik olarak eklenir __proto__ Bu yüzden, eğer değiştirirsek, önceki kod snippet'inde yaptığımız gibi, tüm JavaScript nesneleri değişecek, iyi bir uygulama değil. Peki şimdi daha iyi uygulama ne olabilir:

person.__proto__ = {
    Person: Person,
    getName: getName
};

ve şimdi diğer nesneler barış içinde, ama yine de iyi bir uygulama gibi görünmüyor. Bu yüzden hala bir tane daha çözümümüz var, ama bu çözümü kullanmak için o kod satırına geri dönmeliyiz person nesne oluşturulduvar person = {};) daha sonra aşağıdaki gibi değiştirin:

var propertiesObject = {
    Person: Person,
    getName: getName
};
var person = Object.create(propertiesObject);

ne yapar, yeni bir JavaScript yaratıyor Object ve takın propertiesObject göre __proto__ bağlıyor. Yani yapabileceğinizden emin olmak için:

console.log(person.__proto__===propertiesObject); //true

Fakat buradaki zor nokta, tanımlanmış tüm özelliklere erişebilmenizdir. __proto__ ilk seviyesinde person nesne (daha fazla ayrıntı için özet bölümünü okuyun).


bu iki yoldan birini gördüğünüz gibi this tam olarak person nesne.

c. JavaScript'in işlevi sağlamanın başka bir yolu var this, kullanıyor aramak veya uygulamak işlevi çağırmak için.

Apply () yöntemi verilen bir değerle bir işlevi çağırır ve   bir dizi (veya bir dizi benzeri nesne) olarak sağlanan argümanlar.

ve

Call () yöntemi, verilen bu değerle bir işlevi çağırır ve   bağımsız olarak sunulan argümanlar.

En sevdiğim bu şekilde, aşağıdaki gibi işlevlerimizi kolayca arayabiliriz:

Person.call(person, "George");

veya

//apply is more useful when params count is not fixed
Person.apply(person, ["George"]);

getName.call(person);   
getName.apply(person);

Bu 3 yöntem, .prototype işlevselliğini belirlemek için önemli başlangıç ​​adımlarıdır.


2- Nasıl yapılır new anahtar kelime çalışır?

Bunu anlamak için ikinci adım .prototype function.this işlemi simüle etmek için kullandığım şey:

function Person(name){  this.name = name;  }
my_person_prototype = { getName: function(){ console.log(this.name); } };

bu bölümde, JavaScript'in kullanmadan kullanacağı tüm adımları atmaya çalışacağım. new anahtar kelime ve prototype, kullandığınız zaman new Anahtar kelime. öyle yaptığımızda new Person("George"), Person işlevi bir kurucu olarak hizmet eder, Bunlar JavaScript’in yaptığı şeydir:

a. her şeyden önce boş bir nesne yapar, temelde boş bir karma gibi:

var newObject = {};

b. JavaScript'in alacağı bir sonraki adım iliştirmek Yeni oluşturulan nesneye tüm prototip nesneleri

sahibiz my_person_prototype Burada prototip nesnesine benzer.

for(var key in my_person_prototype){
    newObject[key] = my_person_prototype[key];
}

JavaScript'in prototipte tanımlanan özellikleri gerçekten eklemesi bu şekilde değildir. Gerçek yol prototip zincir kavramı ile ilgilidir.


a. & b. Bu iki adım yerine, aşağıdakileri yaparak aynı sonucu elde edebilirsiniz:

var newObject = Object.create(my_person_prototype);
//here you can check out the __proto__ attribute
console.log(newObject.__proto__ === my_person_prototype); //true
//and also check if you have access to your desired properties
console.log(typeof newObject.getName);//"function"

şimdi arayabiliriz getName bizim fonksiyonumuzda my_person_prototype:

newObject.getName();

c. sonra o nesneyi kurucuya verir,

Bunu bizim örneğimizle yapabiliriz:

Person.call(newObject, "George");

veya

Person.apply(newObject, ["George"]);

o zaman yapıcı istediğini yapabilir, çünkü bu Bu yapıcının içi, yeni yaratılmış olan nesnedir.

şimdi diğer adımları simüle etmeden önce sonuç:     Nesne {name: "George"}


Özet:

Temel olarak, yeni Bir işlevin anahtar sözcüğü, siz bunu çağırıyorsunuz ve bu işlev bir kurucu olarak hizmet veriyor, yani şöyle diyorsunuz:

new FunctionName()

JavaScript dahili olarak bir nesneyi, boş bir kareyi yapar ve sonra bu nesneyi yapıcıya verir, sonra yapıcı istediği her şeyi yapabilir, çünkü bu Bu kurucunun içinde yeni oluşturulmuş olan nesnedir ve daha sonra, eğer fonksiyonunuzda geri dönüş ifadesini kullanmadıysanız ya da return undefined; Fonksiyon bedeninin sonunda.

Bu yüzden, JavaScript bir nesneye bir özellik ararken, yaptığı ilk şey, o nesnenin üzerine bakar. Ve sonra bir gizli özellik var [[prototype]] genellikle buna benziyor __proto__ ve bu özellik, JavaScript'in bir sonraki adımıdır. Ve göründüğünde __proto__Yine başka bir JavaScript nesnesi olduğu sürece, kendi kendine ait __proto__özniteliği, bir sonraki noktaya gelene kadar yukarı ve yukarı gider __proto__ boş. Nokta, JavaScript'indeki tek nesnedir. __proto__ özniteliği boş Object.prototype nesne:

console.log(Object.prototype.__proto__===null);//true

ve bu, kalıtımın JavaScript’de nasıl işlediğidir.

The prototype chain

Başka bir deyişle, bir işlevde bir prototype özelliğiniz olduğunda ve bunun için yeni bir çağrı yaptığınızda, JavaScript, yeni oluşturulan nesneye yönelik özellikleri inceledikten sonra, işlevin işlevine bakacaktır. .prototype ve ayrıca bu nesnenin kendi iç prototipine sahip olması da mümkündür. ve bunun gibi.


163
2018-02-13 19:32



a) Lütfen özellikleri kopyalayarak prototipleri açıklamayın b) Dahili ayarı [[prototip]] constructor işlevi örnek üzerinde uygulanmadan önce gerçekleşir, lütfen bu siparişi değiştirin c) jQuery bu soruda tamamen offtopiktir - Bergi
@Bergi: Dikkat ettiğin için teşekkürler, eğer şimdi sorun olup olmadığını bana bildirsen memnun olurum. - Mehran Hatami
Lütfen bunu basitleştirebilir misin? Her noktada haklısınız, ancak bu açıklamayı okuyan öğrenciler ilk kez gerçekten kafa karıştırıcı olabilirler. Daha basit bir örnek alın ve kodun ne anlama geldiğini açıklığa kavuşturmak için bir açıklama yapmasına izin verin. - P.M
@ P.M: Geri bildiriminiz için teşekkürler. Bunu olabildiğince basit yapmaya çalıştım ama bence haklısınız, bazı belirsiz noktaları var. Bu yüzden onu değiştirmeye çalışacağım ve daha açıklayıcı olacak. :) - Mehran Hatami
"Kitabınızın" sonunda gösterim için +1 - sargas


prototype sınıflar yapmanıza olanak tanır. eğer kullanmazsan prototype sonra statik hale gelir.

İşte kısa bir örnek.

var obj = new Object();
obj.test = function() { alert('Hello?'); };

Yukarıdaki durumda, statik işlev çağrısı testiniz var. Bu işlevin yalnızca bir obj olduğu düşünüp hayal edebileceğiniz obj.test tarafından erişilebilir.

Aşağıdaki kodda olduğu gibi

function obj()
{
}

obj.prototype.test = function() { alert('Hello?'); };
var obj2 = new obj();
obj2.test();

Obj, şimdi örneklenebilecek bir sınıf haline geldi. Birden fazla obj örneği olabilir ve hepsi test işlevi.

Yukarıdaki anlayış benim. Ben bir topluluk wiki yapıyorum, bu yüzden insanlar yanılıyorsam beni düzeltebilirler.


66
2017-11-07 09:48



1: prototype Örnekler değil, yapıcı işlevlerin bir özelliği, yani kodunuz yanlıştır! Belki standart dışı mülk demek istediniz. __proto__ nesnelerin, ama bu tamamen farklı bir canavar ... - Christoph
@Christoph - Bunu işaretlediğiniz için teşekkürler. Örnek kodu güncelledim. - Ramesh
Bu iyi bir cevap, ama daha fazlası var. - John Leidegren
Bunun için çok daha fazlası var ... Artı JavaScript sınıf temelli bir dil değildir - prototipler yoluyla miras ile ilgilenir, farklılıkları daha ayrıntılı olarak ele almanız gerekir! - James
Bu cevabın biraz yanlış olduğunu düşünüyorum. - Armin Cifuentes


Bu konuyu okuduktan sonra, JavaScript Prototype Zinciri ile karıştırıldığını hissediyorum, sonra bu çizelgeleri buldum

http://iwiki.readthedocs.org/en/latest/javascript/js_core.html#inheritance *[[protytype]]* and <code>prototype</code> property of function objects

JavaScript Kalıtımını Prototip Zinciri ile gösterecek açık bir grafik var

ve

http://www.javascriptbank.com/javascript/article/JavaScript_Classical_Inheritance/

Bu kod ve birkaç güzel diyagramları ile bir örnek içerir.

prototip zinciri sonunda Object.prototype'a geri döner.

prototip zinciri, her zaman, alt sınıfın prototipini ana sınıfın nesnesine eşit olacak şekilde istediğiniz kadar teknik olarak genişletilebilir.

Ayrıca, JavaScript Prototip Zinciri'ni anlamanız için de yararlıdır.


59
2018-05-26 20:40



Bağlantıların içeriğinin kısa bir özetini sağlayabilmeniz harika olurdu, bu yüzden bağlantılar kesildiğinde bu cevap hala yararlı olur. - Nicktar
@Nicktar, Öneriniz için teşekkürler, bu bağlantılar tarafından basit bir açıklama ekledim. - rockXrock
açık bir grafik bu mu? :) - Nuno_147
Bir diyagram bin kelimeyi konuşur. Bu çok yararlı :) - Mark Robson
Ne olduğunu açıklayabilir misin [[Prototype]] anlamına geliyor? - CodyBugstein


Prototipin yedi Koans

Ciro San derin meditasyondan sonra Fire Fox Dağı'nı inerken, aklı açık ve huzurluydu.

Ancak eli huzursuzdu ve kendi başına bir fırça aldı ve aşağıdaki notları attı.


0) İki farklı şey "prototip" olarak adlandırılabilir:

  • prototype özelliği, obj.prototype

  • olarak gösterilen prototip dahili özellik [[Prototype]]  ES5'te.

    ES5 üzerinden alınabilir Object.getPrototypeOf().

    Firefox, üzerinden erişilebilir kılar __proto__ bir uzantı olarak özellik. ES6 şimdi bahseder için bazı isteğe bağlı gereksinimler __proto__.


1) Bu kavramlar soruyu cevaplamak için var:

Ben yaparken obj.property, nerede JS arar .property?

Sezgisel olarak, klasik miras özellik arayışını etkilemelidir.


2)

  • __proto__ nokta için kullanılır . özellik aramada olduğu gibi obj.property.
  • .prototype olduğu değil doğrudan arama için kullanılır, sadece dolaylı olarak belirlediği gibi __proto__ nesne oluşturma ile new.

Arama sırası:

  • obj ile eklenen özellikler obj.p = ... veya Object.defineProperty(obj, ...)
  • özellikleri obj.__proto__
  • özellikleri obj.__proto__.__proto__, ve bunun gibi
  • Eğer bazı __proto__ olduğu null, dönüş undefined.

Bu sözde prototip zinciri.

Kaçınabilirsiniz . ile aramak obj.hasOwnProperty('key') ve Object.getOwnPropertyNames(f)


3) Ayarlamanın iki ana yolu vardır obj.__proto__:

  • new:

    var F = function() {}
    var f = new F()
    

    sonra new ayarladı:

    f.__proto__ === F.prototype
    

    Bu nerede .prototype kullanılır.

  • Object.create:

     f = Object.create(proto)
    

    kümeleri:

    f.__proto__ === proto
    

4) Kod:

var F = function() {}
var f = new F()

Aşağıdaki şemaya karşılık gelir:

(Function)       (  F  )                                      (f)
 |  ^             | | ^                                        |
 |  |             | | |                                        |
 |  |             | | +-------------------------+              |
 |  |constructor  | |                           |              |
 |  |             | +--------------+            |              |
 |  |             |                |            |              |
 |  |             |                |            |              |
 |[[Prototype]]   |[[Prototype]]   |prototype   |constructor   |[[Prototype]]
 |  |             |                |            |              |
 |  |             |                |            |              |
 |  |             |                | +----------+              |
 |  |             |                | |                         |
 |  |             |                | | +-----------------------+
 |  |             |                | | |
 v  |             v                v | v
(Function.prototype)              (F.prototype)
 |                                 |
 |                                 |
 |[[Prototype]]                    |[[Prototype]]
 |                                 |
 |                                 |
 | +-------------------------------+
 | |
 v v
(Object.prototype)
 | | ^
 | | |
 | | +---------------------------+
 | |                             |
 | +--------------+              |
 |                |              |
 |                |              |
 |[[Prototype]]   |constructor   |prototype
 |                |              |
 |                |              |
 |                | -------------+
 |                | |
 v                v |
(null)           (Object)

Bu şema, birçok dil önceden tanımlanmış nesne düğümünü göstermektedir: null, Object, Object.prototype, Function ve Function.prototype. 2 satır kodumuz sadece oluşturuldu f, F ve F.prototype.


5)  .constructor normalden geliyor F.prototype içinden . yukarı Bak:

f.constructor === F
!f.hasOwnProperty('constructor')
Object.getPrototypeOf(f) === F.prototype
F.prototype.hasOwnProperty('constructor')
F.prototype.constructor === f.constructor

Yazarken f.constructor, JavaScript yapar . arama olarak:

  • f bulunmamaktadır .constructor
  • f.__proto__ === F.prototype vardır .constructor === F, Öyleyse al

Sonuç f.constructor == F sezgisel olarak doğru F inşa etmek için kullanılır f, Örneğin. Klasik OOP dillerinde olduğu gibi alanları ayarlayın.


6) Prototip zincirleri manipüle edilerek klasik kalıtım sözdizimi sağlanabilir.

ES6 ekler class ve extends Daha önce olası prototip manipülasyon çılgınlığı için sadece sözdizimi şekeri olan anahtar kelimeler.

class C {
    constructor(i) {
        this.i = i
    }
    inc() {
        return this.i + 1
    }
}

class D extends C {
    constructor(i) {
        super(i)
    }
    inc2() {
        return this.i + 2
    }
}
// Inheritance syntax works as expected.
(new C(1)).inc() === 2
(new D(1)).inc() === 2
(new D(1)).inc2() === 3
// "Classes" are just function objects.
C.constructor === Function
C.__proto__ === Function.prototype
D.constructor === Function
// D is a function "indirectly" through the chain.
D.__proto__ === C
D.__proto__.__proto__ === Function.prototype
// "extends" sets up the prototype chain so that base class
// lookups will work as expected
var d = new D(1)
d.__proto__ === D.prototype
D.prototype.__proto__ === C.prototype
// This is what `d.inc` actually does.
d.__proto__.__proto__.inc === C.prototype.inc
// Class variables
// No ES6 syntax sugar apparently:
// http://stackoverflow.com/questions/22528967/es6-class-variable-alternatives
C.c = 1
C.c === 1
// Because `D.__proto__ === C`.
D.c === 1
// Nothing makes this work.
d.c === undefined

Önceden tanımlanmış tüm nesneler olmaksızın basitleştirilmiş şema:

      __proto__
(C)<---------------(D)         (d)
| |                |           |
| |                |           |
| |prototype       |prototype  |__proto__
| |                |           |
| |                |           |
| |                | +---------+
| |                | |
| |                | |
| |                v v
|__proto__        (D.prototype)
| |                |
| |                |
| |                |__proto__
| |                |
| |                |
| | +--------------+
| | |
| | |
| v v
| (C.prototype)--->(inc)
|
v
Function.prototype

57
2018-06-18 19:48



Bunu nereden aldığınızı bilmiyorum ama bu en net cevap! - tomasb
@tomasb teşekkürler! "Bunu nereden aldığımı bilmiyorum": Bu dinamik dillerden birkaçını gördükten sonra, sınıf sistemiyle ilgili en önemli şeyin nasıl olduğunu fark ettim. . arama çalışır (ve verilerin kaç kopyası yapılır). Ben de bu noktayı anlamak için yola çıktım. Kalan, Google + blog gönderileri + elindeki Js tercümanıdır. :) - Ciro Santilli 新疆改造中心 六四事件 法轮功
Bu cevap, bu kavramın doğru ve derin bir anlayışını göstermektedir. Aferin! - Nir Smadar
Ben hala neden g.constructor === noktasını alamıyorum çünkü "4) f = new F'yi yaptığınızda, f.constructor = F" değerini ayarlar. Bana daha fazlasını açıklar mısınız? Her neyse, aradığım en iyi cevap bu. Çok teşekkür ederim! - nguyenngoc101
@Hepsi açık, cevabın için oy verdim. Bana yardım için teşekkür ederim. - nguyenngoc101


Her nesnenin başka bir nesneye bağlandığı dahili bir [[Prototip]] özelliği vardır:

object [[Prototype]] -> anotherObject

Geleneksel javascriptte, bağlantılı nesne prototype Bir fonksiyonun özelliği:

object [[Prototype]] -> aFunction.prototype

Bazı ortamlar [[Prototype]] 'ı __proto__:

anObject.__proto__ === anotherObject

Bir nesne oluştururken [[Prototype]] bağlantısını oluşturursunuz.

// (1) Object.create:
var object = Object.create(anotherObject)
// object.__proto__ = anotherObject

// (2) ES6 object initializer:
var object = { __proto__: anotherObject };
// object.__proto__ = anotherObject

// (3) Traditional JavaScript:
var object = new aFunction;
// object.__proto__ = aFunction.prototype

Yani bu ifadeler eşdeğerdir:

var object = Object.create(Object.prototype);
var object = { __proto__: Object.prototype }; // ES6 only
var object = new Object;

bir new ifade bağlantı hedefini göstermiyor (Object.prototype) kendisi; bunun yerine, hedef yapıcı tarafından ima edilir (Object).

Hatırlamak:

  • Her nesnenin bir bağ, [[Prototip]], bazen __proto__.
  • Her fonksiyonun bir prototype özelliği.
  • İle oluşturulan nesneler new ile bağlantılı prototype kurucularının mülkiyet.
  • Bir işlev hiçbir zaman bir kurucu olarak kullanılmazsa, prototype özellik kullanılmayacak.
  • Bir kurucuya ihtiyacınız yoksa, kullanın Object.create yerine new.

33
2018-02-21 12:41



Object.create () öğesini vurgulamak için +1 - Jakob Sternberg
Revision 5, Object.create () üzerindeki bilgiler dahil olmak üzere bazı yararlı bilgileri kaldırmıştır. Görmek revizyon 4. - Palec
@Palec ne eklemeliyim? - sam
IMO en azından bağlantı Object.create() docs@sam. Bağlantılar __proto__ ve Object.prototype güzel geliştirmeler olurdu. Ve prototiplerin kurucularla nasıl çalıştığı örneklerini beğendim ve Object.create()ama muhtemelen kurtulmak istediğin uzun ve az ilgili kısımlardı. - Palec
Yaptığım tüm tartışmalardan (klasik mirastan geldiğim) yapıcı işlevini yaratırsam ve yeni operatör kullanarak bunun örneğini oluşturmaya çalışırsam, yalnızca proto nesnesine eklenen yöntemleri ve özellikleri alırım, bu nedenle tüm yöntemi eklemek gerekir ve eğer miras almak istiyorsak proto nesnesine özellikler, doğru mu? - blackHawk


Javascript her zamanki anlamda mirasa sahip değil, ama prototip zincirine sahip.

prototip zinciri

Nesnenin bir üyesi nesnede bulunamazsa, prototip zincirinde onu arar. Zincir diğer nesnelerden oluşur. Belirli bir örneğe ait prototip ile erişilebilir. __proto__ değişken. Javascript'teki sınıflar ve örnekler arasında fark olmadığı için her nesnenin bir tane vardır.

Prototipe bir işlev / değişken eklemenin avantajı, her bir örnek için değil, yalnızca bir kez bellekte olması gerektiğidir.

Aynı zamanda kalıtım için de faydalıdır, çünkü prototip zinciri birçok başka nesneden oluşabilir.


23
2017-11-04 14:08



FF ve Chrome destekleri protoama IE ya da Opera değil. - some
Georg, lütfen noob için açıklığa kavuşturun - "javascript'te sınıflar ve örnekler arasında fark yoktur." - detaylandırır mısın? Bu nasıl çalışıyor? - Hamish Grubijan
Yaptığım tüm tartışmalardan (klasik mirastan geldiğim) yapıcı işlevini yaratırsam ve yeni operatör kullanarak bunun örneğini oluşturmaya çalışırsam, yalnızca proto nesnesine eklenen yöntemleri ve özellikleri alırım, bu nedenle tüm yöntemi eklemek gerekir ve eğer miras almak istiyorsak proto nesnesine özellikler, doğru mu? - blackHawk