Prototip yapıcısını ayarlamak neden gereklidir?


294

In MDN makale Devralmayla ilgili bölümde JavaScript nesne yönelimli için giriş , ben onlar prototype.constructor set fark:

// correct the constructor pointer because it points to Person
Student.prototype.constructor = Student;  

Bu önemli bir amaca hizmet ediyor mu? Bunu atlamak uygun mudur?


23
Bunu sorduğunuza sevindim: Dün aynı belgeleri okudum ve kurucuyu da açıkça ayarlamanın ardındaki mantığı merak ettim.
Wylie

6
Sadece bunu belirtmek zorunda kaldım, bu soru bağlandığınız makalede bağlantılı!
Marie

7
hiçbir şey gerekli
16:20

1
subclass.prototype.constructorİşaret eder parent_classyazmıyorsun eğer subclass.prototype.constructor = subclass; Yani, subclass.prototype.constructor()doğrudan kullanmak beklenmedik bir sonuç doğuracaktır.
KuanYu Chu

Yanıtlar:


263

Her zaman gerekli değildir, ancak kullanımları vardır. Temel Personsınıfta bir kopyalama yöntemi yapmak istediğimizi varsayalım . Bunun gibi:

// define the Person Class  
function Person(name) {
    this.name = name;
}  

Person.prototype.copy = function() {  
    // return new Person(this.name); // just as bad
    return new this.constructor(this.name);
};  

// define the Student class  
function Student(name) {  
    Person.call(this, name);
}  

// inherit Person  
Student.prototype = Object.create(Person.prototype);

Şimdi yeni bir tane oluşturup Studentkopyaladığımızda ne olur ?

var student1 = new Student("trinth");  
console.log(student1.copy() instanceof Student); // => false

Kopya bir örneği değil Student. Bunun nedeni, (açık kontroller olmadan), Student"temel" sınıftan bir kopyasını geri döndürmenin hiçbir yolunun olmamasıdır . Biz sadece bir Person. Ancak, yapıcıyı sıfırlamış olsaydık:

// correct the constructor pointer because it points to Person  
Student.prototype.constructor = Student;

... sonra her şey beklendiği gibi çalışır:

var student1 = new Student("trinth");  
console.log(student1.copy() instanceof Student); // => true

34
Not: constructorÖzniteliğin JS'de özel bir anlamı yoktur, bu nedenle onu da çağırabilirsiniz bananashake. Tek fark motoru otomatik olarak başlatır olmasıdır constructorüzerinde f.prototypebir işlev bildirmek zaman f. Ancak, herhangi bir zamanda üzerine yazılabilir.
user123444555621

58
@ Pumbaa80 - Ben olsun puanınızı ama motor otomatik başlatır gerçeği constructorbu araçlar yapar hemen hemen tanımı gereği, JS özel bir anlamı vardır.
Wayne

13
Sadece kullandığından davranış Sorunsuz söyledi nedeni olduğunu açıklığa kavuşturmak istiyorum return new this.constructor(this.name);yerine return new Person(this.name);. Yana this.constructorolduğunu Student(eğer bunu ayarlamak çünkü fonksiyon Student.prototype.constructor = Student;), copyfonksiyon çağırarak biter Studentişlevi. Yorumdaki niyetinizin ne olduğundan emin değilim //just as bad.
CEGRD

12
@lwburk "// kadar kötü" ile ne demek istiyorsun?
CEGRD

6
Sanırım anladım. Ama, ne olursa Student: yapıcı gibi ek bir argüman eklemişti Student(name, id)? Ardından copy, Personsürümü geçersiz kılmalı, içindeki sürümü çağırmalı ve sonra ek idözelliği kopyalamalıyız ?
snapfractalpop

76

Bu önemli bir amaca hizmet ediyor mu?

Evet ve hayır.

ES5 ve öncesinde JavaScript'in kendisi hiçbir constructorşey için kullanmıyordu . Bir işlevin prototypeözelliğindeki varsayılan nesnenin ona sahip olacağını ve işleve geri döneceğini tanımladı ve işte budur . Spesifikasyonda başka hiçbir şey ona hiç atıfta bulunmadı.

Bu, miras hiyerarşilerine göre kullanmaya başlayan ES2015'te (ES6) değişti. Örneğin, Promise#thenkullandığı constructorsen (via üzerine diyoruz sözünün özelliği SpeciesConstructor dönmek için yeni umut oluştururken). Aynı zamanda alt dizileri de dizilerle ilişkilendirir ( ArraySpeciesCreate aracılığıyla ).

Dilin dışında, bazen insanlar genel "klon" işlevleri oluşturmaya çalışırken ya da genellikle nesnenin yapıcı işlevi olduğuna inandıkları şeylere başvurmak istediklerinde onu kullanırlardı. Benim tecrübelerim, onu kullanmanın nadir olduğunu, ancak bazen insanların kullandığını.

Bunu atlamak uygun mudur?

Varsayılan olarak oradadır, yalnızca bir işlevin özelliğindeki nesneyi değiştirdiğinizde geri koymanız gerekir prototype:

Student.prototype = Object.create(Person.prototype);

Bunu yapmazsanız:

Student.prototype.constructor = Student;

... sonra (muhtemelen) sahip olduğu Student.prototype.constructormiras . Bu yüzden yanıltıcı. Ve elbette, onu kullanan ( veya gibi ) bir şeyi alt sınıflara alıyorsanız ve ¹ (bunu sizin için halleder ) kullanmıyorsanız , doğru ayarladığınızdan emin olmak istersiniz. Temel olarak: İyi bir fikir.Person.prototypeconstructor = PersonPromiseArrayclass

Kodunuzda (veya kullandığınız kitaplık kodunda) hiçbir şey kullanılmıyorsa sorun yoktur. Her zaman doğru bağlandığından emin oldum.

Tabii ki, ES2015 (aka ES6) classanahtar kelimesiyle, çoğu zaman onu kullanırdık, artık zorunda değiliz, çünkü bunu yaptığımızda bizim için halledilir

class Student extends Person {
}

¹ "... Eğer (gibi kullanır bunu o şey sınıflara eğer Promiseya Array) ve kullanma class..."  - It mümkün bunu yapmak için, ama bu gerçek bir ağrı var (ve biraz saçma). Kullanmak zorundasın Reflect.construct.


12

TLDR; Süper gerekli değildir, ancak muhtemelen uzun vadede yardımcı olacaktır ve bunu yapmak daha doğrudur.

NOT: Önceki cevabım kafa karıştırıcı bir şekilde yazılmış ve cevaplamak için acele ettiğim bazı hatalar olduğu için çok fazla düzenlenmişti. Bazı korkunç hatalara dikkat çekenlere teşekkürler.

Temel olarak, Javascript alt sınıflandırma doğru tel bağlamaktır. Alt sınıfa girdiğimizde, prototip delegasyonunun bir prototypenesnenin üzerine yazılması da dahil olmak üzere düzgün çalıştığından emin olmak için bazı korkak şeyler yapmalıyız . Bir prototypenesnenin üzerine yazmak constructor, bu nedenle referansı düzeltmemiz gerekir.

ES5'teki 'sınıfların' nasıl çalıştığını hızlıca inceleyelim.

Diyelim ki bir yapıcı işleviniz ve onun prototipi var:

//Constructor Function
var Person = function(name, age) {
  this.name = name;
  this.age = age;
}

//Prototype Object - shared between all instances of Person
Person.prototype = {
  species: 'human',
}

Kurucuyu somutlaştırmak için çağırdığınızda şunları söyleyin Adam:

// instantiate using the 'new' keyword
var adam = new Person('Adam', 19);

new'Kişi' ile çağrılan anahtar kelime temelde kod birkaç ek çizgilerle Kişi yapıcısı çalışacaktır:

function Person (name, age) {
  // This additional line is automatically added by the keyword 'new'
  // it sets up the relationship between the instance and the prototype object
  // So that the instance will delegate to the Prototype object
  this = Object.create(Person.prototype);

  this.name = name;
  this.age = age;

  return this;
}

/* So 'adam' will be an object that looks like this:
 * {
 *   name: 'Adam',
 *   age: 19
 * }
 */

Biz ise console.log(adam.species), arama başarısız olur adammesela ve onun için prototypal zincirini bakmak .prototypeolduğunu Person.prototype- ve Person.prototype sahip bir .speciesarama başarılı olur, böylece özelliği Person.prototype. Daha sonra günlüğe kaydedilir 'human'.

Burada, Person.prototype.constructordoğru bir şekilde işaret edecektir Person.

Şimdi ilginç kısım, sözde 'alt sınıflama'. Bir Studentsınıf oluşturmak istiyorsak , bu Personbazı ek değişikliklerle sınıfın bir alt sınıfıdır, Student.prototype.constructordoğruluk için Öğrenci'ye işaret ettiğinden emin olmamız gerekir .

Bunu tek başına yapmaz. Alt sınıf oluşturduğunuzda, kod şöyle görünür:

var Student = function(name, age, school) {
 // Calls the 'super' class, as every student is an instance of a Person
 Person.call(this, name, age);
 // This is what makes the Student instances different
 this.school = school
}

var eve = new Student('Eve', 20, 'UCSF');

console.log(Student.prototype); // this will be an empty object: {}

new Student()Burada çağrı yapmak istediğimiz tüm özelliklere sahip bir nesne döndürür. Burada, kontrol edersek eve instanceof Person, dönecekti false. Eğer erişmeye çalışırsak eve.species, geri dönecekti undefined.

Başka bir deyişle, delege doğru şekilde eve instanceof Persondönecek ve Studentdelege örnekleri doğru bir şekilde Student.prototypeve sonra olacak şekilde kablolamalıyız Person.prototype.

AMA newanahtar kelimeyle çağırdığımızdan , bu çağrının ne eklediğini hatırlıyor musunuz? Buna Object.create(Student.prototype), Studentve arasındaki delegasyonel ilişkiyi böyle kurduk Student.prototype. Şu anda Student.prototypeboş olduğunu unutmayın . Bu nedenle, .speciesbir örneğini aramak yalnızcaStudent temsilci seçerken başarısız olur ve mülk üzerinde mevcut değildir . Student.prototype.speciesStudent.prototype

Biz atama yaptığımızda Student.prototypeiçin Object.create(Person.prototype), Student.prototypeiçin kendisi daha sonra delegelere Person.prototypeve yukarı seyir eve.speciesdönecektir humanbeklediğimiz gibi. Muhtemelen Student.prototype AND Person.prototype'den miras almasını isteriz. Yani hepsini düzeltmemiz gerekiyor.

/* This sets up the prototypal delegation correctly 
 *so that if a lookup fails on Student.prototype, it would delegate to Person's .prototype
 *This also allows us to add more things to Student.prototype 
 *that Person.prototype may not have
 *So now a failed lookup on an instance of Student 
 *will first look at Student.prototype, 
 *and failing that, go to Person.prototype (and failing /that/, where do we think it'll go?)
*/
Student.prototype = Object.create(Person.prototype);

Şimdi delegasyon çalışıyor, ancak Student.prototypebir ile yazıyoruz Person.prototype. Eğer ararsak Student.prototype.constructor, bunun Personyerine işaret eder Student. Bu yüzden düzeltmemiz gerekiyor.

// Now we fix what the .constructor property is pointing to    
Student.prototype.constructor = Student

// If we check instanceof here
console.log(eve instanceof Person) // true

ES5'te, mülkümüz constructor'yapıcı' olma niyetiyle yazdığımız bir işleve gönderme yapan bir referanstır. newAnahtar kelimenin bize verdiklerinin yanı sıra , yapıcı aksi takdirde 'düz' bir işlevdir.

ES6'da, constructorşimdi sınıf yazma şeklimizde yerleşiktir - olduğu gibi, bir sınıf ilan ettiğimizde bir yöntem olarak sağlanır. Bu sadece sözdizimsel şekerdir, ancak var superolan bir sınıfı genişletirken bir zamana erişim gibi bazı kolaylıklar sağlıyor . Yani yukarıdaki kodu şöyle yazardık:

class Person {
  // constructor function here
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
  // static getter instead of a static property
  static get species() {
    return 'human';
  }
}

class Student extends Person {
   constructor(name, age, school) {
      // calling the superclass constructor
      super(name, age);
      this.school = school;
   }
}

eve instanceof Studentdöndü true. Açıklama için stackoverflow.com/questions/35537995/… adresine bakın . Ayrıca ne demek istediğinizi söylediğinizde which is, at the moment, nothing? Her fonksiyonun bir prototipi vardır, bu yüzden kontrol edersem bir Student.prototypeşeydir.
Aseem Bansal

Benim hatam. Yanlış dönecek olan 'Eve instanceof' örneğini okumuş olmalıydı. O kısmı değiştireceğim. Her işlevin bir prototip özelliğine sahip olduğu doğrudur. Ancak , hiç prototip atamadan Object.create(Person.prototype), Student.prototypeboştur. Dolayısıyla, giriş yaparsak eve.species, üst sınıfına, Kişiye uygun şekilde yetki vermez ve giriş yapmaz 'human'. Muhtemelen, her alt sınıfın prototipinden ve ayrıca süper prototipinden miras almasını istiyoruz.
bthehuman

Açıklamak için which is, at the moment, nothing, Student.prototypenesnenin boş olduğunu kastediyorum .
bthehuman

Daha prototip üzerinde: atanması olmadan Student.prototypeiçin Object.create(Person.prototype)- hatırlarsan vardır, aynı şekilde Kişinin tüm örnekleri için temsilciye ayarlanmıştır Person.prototypeörneğinde bir özellik ararken - Studentürününün yetki istiyorum sadece Student.prototype . Böylece eve.speciesarama başarısız olur. Eğer onu atarsak, Student.prototypekendisi delege olur Person.prototypeve yukarıya bakmak eve.speciesgeri döner human.
bthehuman

Görünüşe göre burada yanlış olan birkaç şey var: "'Alt sınıfı' taklit etmeye çalıştığınızda [...] gereklidir, böylece bir örneğin instance'alt sınıf' Yapıcısı olup olmadığını kontrol ettiğinizde doğru olur." Hayır, instanceofkullanmayın constructor. "Ancak, öğrencinin .prototype.constructor'ına bakarsak, yine de Kişiye işaret eder" Hayır, öyle olacaktır Student. Bu örneğin amacını anlamıyorum. Bir yapıcıdaki bir işlevi çağırmak kalıtım değildir. "ES6'da yapıcı artık bir işleve başvuru yerine gerçek bir işlevdir" Uh what?
Felix Kling

10

Kabul etmem. Prototipi ayarlamak gerekli değildir. Aynı kodu alın, ancak prototype.constructor satırını kaldırın. Değişen bir şey var mı? Hayır. Şimdi, aşağıdaki değişiklikleri yapın:

Person = function () {
    this.favoriteColor = 'black';
}

Student = function () {
    Person.call(this);
    this.favoriteColor = 'blue';
}

ve test kodunun sonunda ...

alert(student1.favoriteColor);

Renk mavi olacaktır.

Benim deneyimime göre prototip.constructor'da yapılan bir değişiklik, muhtemelen zaten iyi bir uygulama olmayan çok spesifik, çok karmaşık şeyler yapmadığınız sürece fazla bir şey yapmaz :)

Düzenleme: Biraz web etrafında alay ve bazı deneyler yaptıktan sonra insanlar 'yeni' ile inşa ediliyor şey gibi görünüyor 'kurucu ayarlayın gibi görünüyor. Sanırım bununla ilgili sorunun javascript'in prototip bir dil olduğunu iddia ediyorum - kalıtım diye bir şey yok. Ancak çoğu programcı, kalıtımın 'yol' olduğunu iten bir programlama geçmişinden gelir. Bu yüzden bu prototip dili 'sınıfları' genişletmek gibi 'klasik' bir dil haline getirmek için her türlü şeyi buluyoruz. Gerçekten, verdikleri örnekte, yeni bir öğrenci bir kişidir - başka bir öğrenciden 'genişlemez' .. öğrenci tamamen kişiyle ilgilidir ve öğrenci ne olursa olsun. Öğrenciyi ve her neyi genişletirseniz '

Crockford biraz çılgın ve çok hevesli, ama yazdığı bazı şeyleri ciddi bir şekilde okuyun .. bu şeylere çok farklı bakmanızı sağlayacak.


8
Bu, prototip zincirini devralmaz.
Cypher

1
@Cepher yavaş alkış dört yıl sonra konuşmaya hoş geldiniz. Evet, prototip zinciri olan bakılmaksızın prototype.constructor üzerine olsun, miras. Test etmeyi deneyin.
Stephen

7
Prototipi devralan kodu kaçırıyorsunuz. İnternete hoş geldiniz.
Cypher

1
@Cypher Kod snippet'i, bağlı makaledeki koda dayanıyordu. Soruyu bütünüyle okumaya hoş geldiniz. Ah. Bekle.
Stephen

1
@macher klasik kalıtım demek istedim. Benim açımdan kötü ifade seçimi.
Stephen

9

Bu, eğer yazdıysanız,

Student.prototype.constructor = Student;

ama sonra prototipi de Kişi olan bir Öğretmen varsa ve siz

Teacher.prototype.constructor = Teacher;

o zaman Öğrenci kurucusu şimdi Öğretmen!

Düzenleme: Mozilla örneğinde olduğu gibi Object.create kullanılarak oluşturulan Person sınıfının yeni örneklerini kullanarak Öğrenci ve Öğretmen prototiplerini ayarladığınızdan emin olabilirsiniz.

Student.prototype = Object.create(Person.prototype);
Teacher.prototype = Object.create(Person.prototype);

1
Student.prototype = Object.create(...)bu soruda varsayılmıştır. Bu cevap olası karışıklıktan başka bir şey katmıyor.
André Chalella

3
@ AndréNeves Bu cevabı faydalı buldum. Object.create(...)soruyu oluşturan MDN makalesinde kullanılır, ancak sorunun kendisinde kullanılmaz. Eminim birçok insan tıklamaz.
Alex Ross

Alreay sorusunda başvurulan bağlantılı makale Object.create () kullanır. Bu cevap ve Cevabı düzenle gerçekten alakalı değil ve en azından söylemek kafa karıştırıcı :-)
Drenai

1
Daha geniş nokta, Javascript prototiplerine yeni insanları sokacak gotchas olmasıdır. 2016'da tartışacaksak, gerçekten ES6 sınıfları, Babel ve / veya Dizgi metinlerini kullanmalısınız. Ancak sınıfları gerçekten bu şekilde manuel olarak oluşturmak istiyorsanız, prototip zincirlerinin güçlerini artırmak için gerçekten nasıl çalıştığını anlamanıza yardımcı olur. Herhangi bir nesneyi prototip olarak kullanabilirsiniz ve belki de ayrı bir nesne oluşturmak istemezsiniz. Ayrıca, HTML 5 tamamen yaygınlaşmadan önce, Object.create her zaman mevcut değildi, bu nedenle bir sınıfı yanlış ayarlamak daha kolaydı.
James D

5

Şimdiye kadar karışıklık hala var.

Orijinal örneği izleyerek, var olan bir nesneye sahip olduğunuz için student1:

var student1 = new Student("Janet", "Applied Physics");

Nasıl student1oluşturulduğunu bilmek istemediğinizi, bunun gibi başka bir nesneyi istediğinizi varsayalım , student1like yapıcı özelliğini kullanabilirsiniz :

var student2 = new student1.constructor("Mark", "Object-Oriented JavaScript");

Burada Studentyapıcı özelliği ayarlanmamışsa özellikleri almak başarısız olur . Bunun yerine bir Personnesne yaratacaktır .


2

Prototip yapıcısını ayarlamak için neden gerekli olduğuna dair güzel bir kod örneği var.

function CarFactory(name){ 
   this.name=name;  
} 
CarFactory.prototype.CreateNewCar = function(){ 
    return new this.constructor("New Car "+ this.name); 
} 
CarFactory.prototype.toString=function(){ 
    return 'Car Factory ' + this.name;
} 

AudiFactory.prototype = new CarFactory();      // Here's where the inheritance occurs 
AudiFactory.prototype.constructor=AudiFactory;       // Otherwise instances of Audi would have a constructor of Car 

function AudiFactory(name){ 
    this.name=name;
} 

AudiFactory.prototype.toString=function(){ 
    return 'Audi Factory ' + this.name;
} 

var myAudiFactory = new AudiFactory('');
  alert('Hay your new ' + myAudiFactory + ' is ready.. Start Producing new audi cars !!! ');            

var newCar =  myAudiFactory.CreateNewCar(); // calls a method inherited from CarFactory 
alert(newCar); 

/*
Without resetting prototype constructor back to instance, new cars will not come from New Audi factory, Instead it will come from car factory ( base class )..   Dont we want our new car from Audi factory ???? 
*/

Sizin createNewCaryönteminiz fabrikalar yaratmak !? Ayrıca bu var audiFactory = new CarFactory("Audi"), miras kullanmaktan ziyade kullanılmış gibi görünüyor .
Bergi

Örneğiniz this.constructordahili olarak kullanıldığından , ayarlanması şaşırtıcı değildir. Onsuz herhangi bir örneğiniz var mı?
Dmitri Zaitsev

1

Günümüzde şekerli 'sınıflar' fonksiyonuna veya 'Yeni' kullanmaya gerek yok. Nesne değişmez değerleri kullanın.

Nesne prototipi zaten bir 'sınıf'. Bir nesne değişmezi tanımladığınızda, bu nesne zaten Prototip nesnesinin bir örneğidir. Bunlar ayrıca başka bir nesnenin prototipi vb.

const Person = {
  name: '[Person.name]',
  greeting: function() {
    console.log( `My name is ${ this.name || '[Name not assigned]' }` );
  }
};
// Person.greeting = function() {...} // or define outside the obj if you must

// Object.create version
const john = Object.create( Person );
john.name = 'John';
console.log( john.name ); // John
john.greeting(); // My name is John 
// Define new greeting method
john.greeting = function() {
    console.log( `Hi, my name is ${ this.name }` )
};
john.greeting(); // Hi, my name is John

// Object.assign version
const jane = Object.assign( Person, { name: 'Jane' } );
console.log( jane.name ); // Jane
// Original greeting
jane.greeting(); // My name is Jane 

// Original Person obj is unaffected
console.log( Person.name ); // [Person.name]
console.log( Person.greeting() ); // My name is [Person.name]

Bu okumaya değer :

Java ve C ++ gibi sınıfa dayalı nesne yönelimli diller, iki farklı varlık kavramı üzerine kurulmuştur: sınıflar ve örnekler.

...

JavaScript gibi prototip tabanlı bir dil bu ayrımı yapmaz: sadece nesneleri vardır. Prototip tabanlı bir dil, şablon olarak kullanılan ve yeni bir nesnenin başlangıç ​​özelliklerini almak için kullanılan bir nesne olan prototip bir nesne kavramına sahiptir. Herhangi bir nesne, oluşturduğunuzda veya çalışma zamanında kendi özelliklerini belirtebilir. Ek olarak, herhangi bir nesne başka bir nesnenin prototipi olarak ilişkilendirilebilir ve böylece ikinci nesnenin ilk nesnenin özelliklerini paylaşmasına izin verilir


1

toStringMaymunla mücadele olmadan bir alternatife ihtiyacınız olduğunda gereklidir :

//Local
foo = [];
foo.toUpperCase = String(foo).toUpperCase;
foo.push("a");
foo.toUpperCase();

//Global
foo = [];
window.toUpperCase = function (obj) {return String(obj).toUpperCase();}
foo.push("a");
toUpperCase(foo);

//Prototype
foo = [];
Array.prototype.toUpperCase = String.prototype.toUpperCase;
foo.push("a");
foo.toUpperCase();

//toString alternative via Prototype constructor
foo = [];
Array.prototype.constructor = String.prototype.toUpperCase;
foo.push("a,b");
foo.constructor();

//toString override
var foo = [];
foo.push("a");
var bar = String(foo);
foo.toString = function() { return bar.toUpperCase(); }
foo.toString();

//Object prototype as a function
Math.prototype = function(char){return Math.prototype[char]};
Math.prototype.constructor = function() 
  {
  var i = 0, unicode = {}, zero_padding = "0000", max = 9999;
  
  while (i < max) 
    {
    Math.prototype[String.fromCharCode(parseInt(i, 16))] = ("u" + zero_padding + i).substr(-4);

    i = i + 1;
    }    
  }

Math.prototype.constructor();
console.log(Math.prototype("a") );
console.log(Math.prototype["a"] );
console.log(Math.prototype("a") === Math.prototype["a"]);


Bunlardan herhangi biri ne yapmalı? foo.constructor()??
Ry-

0

EDIT, aslında yanılmışım. Hattın yorumlanması, davranışını hiç değiştirmez. (Test ettim)


Evet, gerekli. Ne zaman yaparsın

Student.prototype = new Person();  

Student.prototype.constructorolur Person. Bu nedenle, çağrı Student(), tarafından oluşturulan bir nesneyi döndürür Person. Eğer yaparsan

Student.prototype.constructor = Student; 

Student.prototype.constructorolarak sıfırlanır Student. Şimdi çağırdığınızda, üst Student()yapıcıyı Studentçağıran yürütülür , Parent()doğru devralınan nesneyi döndürür. Aramadan Student.prototype.constructorönce sıfırlamadıysanız , özelliklerden herhangi birine sahip olmayan bir nesne alırsınız Student().


3
Prototip yapısı bir kişi olabilir, ancak Kişiden tüm özellikleri ve yöntemleri miras aldığı için uygundur. Prototype.constructor öğesini ayarlamadan yeni bir Student () oluşturmak kendi yapıcısını uygun şekilde çağırır.
Stephen

0

Basit yapıcı işlevi verildiğinde:

function Person(){
    this.name = 'test';
}


console.log(Person.prototype.constructor) // function Person(){...}

Person.prototype = { //constructor in this case is Object
    sayName: function(){
        return this.name;
    }
}

var person = new Person();
console.log(person instanceof Person); //true
console.log(person.sayName()); //test
console.log(Person.prototype.constructor) // function Object(){...}

Varsayılan olarak ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor belirtiminden ), tüm prototipler otomatik olarak üzerindeki işleve işaret eden yapıcı adı verilen bir özellik alır ki bu bir mülktür. Yapıcıya bağlı olarak, çok yaygın bir uygulama olmayan ancak yine de uzantılar için izin verilen prototipe başka özellikler ve yöntemler eklenebilir.

Bu yüzden basitçe cevaplamak gerekirse: prototip.constructor öğesindeki değerin, belirtilmesi gereken gibi doğru ayarlandığından emin olmamız gerekir.

Bu değeri her zaman doğru ayarlamamız gerekir mi? Hata ayıklamaya yardımcı olur ve iç yapıyı spesifikasyonlara uygun hale getirir. API'mız üçüncü taraflar tarafından kullanıldığında kesinlikle, ancak kod nihayet çalışma zamanında yürütüldüğünde kesinlikle olmamalıdır.


0

MDN'den, kullanımlarını anlamak için çok yararlı bulduğum bir örnek.

JavaScript'te, async functionshangi AsyncFunction nesnesini döndürür . AsyncFunctionglobal bir nesne değildir, ancak constructorözelliği kullanarak nesneyi alabilir ve kullanabilir.

function resolveAfter2Seconds(x) {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(x);
    }, 2000);
  });
}

// AsyncFunction constructor
var AsyncFunction = Object.getPrototypeOf(async function(){}).constructor

var a = new AsyncFunction('a', 
                          'b', 
                          'return await resolveAfter2Seconds(a) + await resolveAfter2Seconds(b);');

a(10, 20).then(v => {
  console.log(v); // prints 30 after 4 seconds
});

-1

Bu gerekli değil. Geleneksel olan birçok şeyden sadece biri, OOP şampiyonları JavaScript'in prototip mirasını klasik mirasa dönüştürmeye çalışıyorlar. Aşağıdaki tek şey

Student.prototype.constructor = Student; 

şimdi geçerli "yapıcı" bir referans var olmasıdır.

Wayne'in cevabında, bu doğru olarak işaretlendi, aşağıdaki kodun yaptığı ile aynı şey olabilir

Person.prototype.copy = function() {  
    // return new Person(this.name); // just as bad
    return new this.constructor(this.name);
};  

aşağıdaki kodla (bunu değiştirin. yapıcıyı Kişi ile değiştirin)

Person.prototype.copy = function() {  
    // return new Person(this.name); // just as bad
    return new Person(this.name);
}; 

Şükürler olsun ki, ES6 klasik kalıtım pistleri dil, sınıf, genişletme ve süper gibi yerli operatörleri kullanabilir ve prototip gibi düşünmek zorunda değiliz. Yapıcı düzeltmeleri ve ebeveyn referansları.

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.