प्रोटोटाइप निर्माता को सेट करना क्यों आवश्यक है?


294

एमडीएन लेख में विरासत के बारे में अनुभाग में ऑब्जेक्ट ओरिएंटेड जावास्क्रिप्ट का परिचय , मैंने देखा कि वे प्रोटोटाइप को सेट करते हैं।

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

क्या इससे कोई महत्वपूर्ण उद्देश्य पूरा होता है? क्या इसे छोड़ना ठीक है?


23
खुशी है कि आपने यह पूछा: मैंने कल भी उसी दस्तावेज को पढ़ा और स्पष्ट रूप से निर्माणकर्ता के रूप में अच्छी तरह से स्थापित करने के पीछे तर्क के बारे में उत्सुक था।
वायली

6
मुझे सिर्फ यह इंगित करना था, यह प्रश्न अब आपके द्वारा लिंक किए गए लेख में जुड़ा हुआ है!
मैरी

7
कुछ भी आवश्यक नहीं है
कुछ

1
subclass.prototype.constructorको इंगित करेगा parent_classअगर तुम नहीं लिखते subclass.prototype.constructor = subclass; यही है, subclass.prototype.constructor()सीधे उपयोग करने से अप्रत्याशित परिणाम होगा।
कुआनयू चू

जवाबों:


263

यह हमेशा आवश्यक नहीं है, लेकिन इसके उपयोग हैं। मान लीजिए कि हम बेस Personक्लास पर एक कॉपी विधि बनाना चाहते थे । ऐशे ही:

// 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);

अब क्या होता है जब हम एक नया बनाते हैं Studentऔर इसे कॉपी करते हैं?

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

प्रति का एक उदाहरण नहीं है Student। ऐसा इसलिए है क्योंकि (स्पष्ट जाँच के बिना), हमारे पास Student"आधार" वर्ग से कॉपी वापस करने का कोई तरीका नहीं है । हम केवल एक वापसी कर सकते हैंPerson । हालाँकि, अगर हमने कंस्ट्रक्टर को रीसेट कर दिया था:

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

... तो सब कुछ उम्मीद के मुताबिक काम करता है:

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

34
नोट: constructorजेएस में विशेषता का कोई विशेष अर्थ नहीं है, इसलिए आप इसे कॉल कर सकते हैं bananashake। फर्क सिर्फ इतना है कि इंजन स्वतः initializes है constructorपर f.prototypeजब भी आप एक समारोह की घोषणा f। हालाँकि, इसे किसी भी समय अधिलेखित किया जा सकता है।
user123444555621

58
@ Pumbaa80 - मैं अपनी बात है, लेकिन तथ्य यह है कि इंजन स्वतः आरंभ पाने constructorका मतलब यह है कि करता है , काफी परिभाषा से जे एस में विशेष अर्थ नहीं होता।
वेन

13
मैं केवल यह स्पष्ट करना चाहता हूं कि आपके द्वारा कहे गए व्यवहार का कारण है क्योंकि आप return new this.constructor(this.name);इसके बजाय उपयोग करते हैं return new Person(this.name);। के बाद से this.constructorहै Studentसमारोह (क्योंकि आप इसे के साथ सेट Student.prototype.constructor = Student;), copyफ़ंक्शन को कॉल समाप्त होता है Studentकार्य करते हैं। मुझे यकीन नहीं है कि //just as badटिप्पणी के साथ आपका इरादा क्या था ।
CEGRD

12
@lwburk का क्या मतलब है "// बस के रूप में बुरा"?
CEGRD

6
मुझे लगता है कि मैंने इसे पा लिया है। लेकिन, क्या होगा अगर Studentनिर्माणकर्ता ने एक अतिरिक्त तर्क जोड़ा है जैसे Student(name, id):? क्या तब हमें copyफ़ंक्शन को ओवरराइड करना Personहोगा, इसके भीतर से संस्करण को कॉल करना होगा, और फिर अतिरिक्त idसंपत्ति की नकल भी करनी होगी ?
Snapfractalpop

76

क्या इससे कोई महत्वपूर्ण उद्देश्य पूरा होता है?

हां और ना।

ईएस 5 और उससे पहले में, जावास्क्रिप्ट स्वयं किसी constructorभी चीज के लिए उपयोग नहीं करता था । यह परिभाषित करता है कि किसी फ़ंक्शन की prototypeसंपत्ति पर डिफ़ॉल्ट ऑब्जेक्ट में यह होगा और यह फ़ंक्शन को वापस संदर्भित करेगा, और वह यह था । विनिर्देश में और कुछ भी नहीं है।

यह ES2015 (ES6) में बदल गया, जिसने विरासत वंशानुक्रम के संबंध में इसका उपयोग करना शुरू कर दिया। उदाहरण के लिए, जब आप लौटने के नए वादे का निर्माण करते हैं , Promise#thenतो constructorप्रॉपर्टी का उपयोग आप इसे ( SpeciesConstructor के माध्यम से ) करते हैं। यह एर्रेस्पेक्टिसक्रिएट के माध्यम से सरणियों को घटाने में भी शामिल है )।

भाषा के बाहर, कभी-कभी लोग इसका उपयोग तब करते हैं जब सामान्य "क्लोन" फ़ंक्शन बनाने की कोशिश करते हैं या आम तौर पर जब वे यह संदर्भित करना चाहते थे कि उनका मानना ​​है कि ऑब्जेक्ट का निर्माता फ़ंक्शन क्या होगा। मेरा अनुभव है कि इसका उपयोग करना दुर्लभ है, लेकिन कभी-कभी लोग इसका उपयोग करते हैं।

क्या इसे छोड़ना ठीक है?

यह डिफ़ॉल्ट रूप से होता है, आपको किसी फ़ंक्शन की संपत्ति पर ऑब्जेक्ट को प्रतिस्थापित करने पर इसे वापस रखने की आवश्यकता होती है prototype:

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

यदि आप ऐसा नहीं करते हैं:

Student.prototype.constructor = Student;

... तो Student.prototype.constructorविरासत में मिला है Person.prototypeजो (संभवतः) है constructor = Person। तो यह भ्रामक है। और निश्चित रूप से, यदि आप किसी ऐसी चीज़ का उपवर्ग कर रहे हैं जो इसका उपयोग (जैसे Promiseया Array) करती है और उपयोग नहीं कर रही हैclass (जो आपके लिए इसे संभालती है , तो आप यह सुनिश्चित करना चाहेंगे कि आप इसे सही तरीके से सेट करें। तो मूल रूप से: यह एक अच्छा विचार है।

यह ठीक है अगर आपके कोड (या आपके द्वारा उपयोग किए जाने वाले पुस्तकालय कोड) में कुछ भी इसका उपयोग नहीं करता है। मैंने हमेशा सुनिश्चित किया है कि इसे सही ढंग से वायर्ड किया गया था।

बेशक, ES2015 (उर्फ ES6) के classकीवर्ड के साथ, अधिकांश समय जब हमने इसका उपयोग किया होगा, तो हमें अब और नहीं करना होगा, क्योंकि जब हम करते हैं तो यह हमारे लिए नियंत्रित होता है।

class Student extends Person {
}

¹ "... यदि आप किसी ऐसी चीज़ का उपवर्ग कर रहे हैं जो इसका उपयोग (जैसे Promiseया Array) और उपयोग नहीं कर रही है class..."  - ऐसा करना संभव है, लेकिन यह एक वास्तविक दर्द है (और थोड़ा मूर्खतापूर्ण)। आपको उपयोग करना होगा Reflect.construct


12

TLDR; सुपर आवश्यक नहीं है, लेकिन संभवतः लंबे समय में मदद करेगा, और ऐसा करना अधिक सटीक है।

नोट: मेरे पिछले उत्तर के रूप में बहुत संपादित किया गया था भ्रामक रूप से लिखा गया था और इसमें कुछ त्रुटियां थीं, जिनका उत्तर देने के लिए मैं जल्दबाज़ी में चूक गया। उन लोगों के लिए धन्यवाद जिन्होंने कुछ अहंकारी त्रुटियों को इंगित किया।

मूल रूप से, यह जावास्क्रिप्ट में सबक्लासिंग को सही ढंग से तार करना है। जब हम उपवर्ग करते हैं, तो हमें यह सुनिश्चित करने के लिए कुछ फंकी चीजें करनी पड़ती हैं कि एक prototypeवस्तु को अधिलेखित करने में प्रोटोटाइप का प्रतिनिधिमंडल सही ढंग से काम करता है । किसी prototypeऑब्जेक्ट को ओवरराइट करने में ऑब्जेक्ट शामिल होता हैconstructor , इसलिए हमें संदर्भ को ठीक करने की आवश्यकता है।

आइए जल्दी से ईएस 5 काम में 'क्लास' कैसे करें।

मान लीजिए कि आपके पास एक निर्माण कार्य और इसका प्रोटोटाइप है:

//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',
}

जब आप कंस्ट्रक्टर को तुरंत फोन करते हैं, तो कहें Adam:

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

newकीवर्ड 'व्यक्ति' के साथ आमंत्रण को मूल रूप से कोड की कुछ अतिरिक्त लाइनों के साथ व्यक्ति निर्माता चलेंगे:

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
 * }
 */

अगर हम console.log(adam.species), देखने में असफल हो जायेगी adamउदाहरण है, और इसके लिए मूलरूप श्रृंखला को देखने के .prototype, जो है Person.prototype- और Person.prototype है एक .speciesसंपत्ति है, तो देखने में सफल होगा Person.prototype। इसके बाद लॉग होगा'human'

यहाँ, Person.prototype.constructorसही ढंग से इंगित करेगा Person

तो अब दिलचस्प हिस्सा है, तथाकथित 'उपवर्ग'। यदि हम एक Studentक्लास बनाना चाहते हैं , जो कि Personकुछ अतिरिक्त परिवर्तनों के साथ क्लास का एक उपवर्ग है , तो हमें यह सुनिश्चित करने की आवश्यकता होगी कि Student.prototype.constructorछात्र सटीकता के लिए अंक प्राप्त करें।

यह खुद से ऐसा नहीं करता है। जब आप उपवर्ग करते हैं, तो कोड इस तरह दिखता है:

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()यहां कॉलिंग उन सभी गुणों के साथ एक ऑब्जेक्ट लौटाएगी जिन्हें हम चाहते हैं। यहां, अगर हम जांच करते हैं eve instanceof Person, तो यह वापस आ जाएगी false। यदि हम एक्सेस करने की कोशिश करते हैं eve.species, तो यह वापस आ जाएगीundefined

दूसरे शब्दों में, हमें प्रतिनिधिमंडल को तार-तार करने की आवश्यकता है ताकि यह eve instanceof Personसही हो जाए और Studentप्रतिनिधि के उदाहरणों को सही ढंग से Student.prototypeऔर फिर Person.prototype

लेकिन जब से हम इसे newकीवर्ड के साथ बुला रहे हैं , याद रखें कि क्या मंगलाचरण जोड़ता है? यह कॉल करेगा Object.create(Student.prototype), कि हम किस तरह से उस प्रतिनिधि संबंध को स्थापित करते हैं Studentऔर Student.prototype। ध्यान दें कि अभी Student.prototypeखाली है। इसलिए .speciesइसका उदाहरण देखने में Studentविफल हो जाएगा क्योंकि यह केवल प्रतिनिधि को सौंपता है Student.prototype, और .speciesसंपत्ति मौजूद नहीं है Student.prototype

जब हम नियत कर सकता Student.prototypeकरने के लिए Object.create(Person.prototype), Student.prototypeअपने आप में तो प्रतिनिधियों Person.prototype, और को देख eve.speciesवापस आ जाएगी human, जैसा कि हम उम्मीद करते हैं। संभवत: हम चाहते हैं कि यह Student.prototype और Person.prototype से विरासत में मिले। तो हम सब को ठीक करने की जरूरत है।

/* 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);

अब प्रतिनिधिमंडल काम करता है, लेकिन हम Student.prototypeएक के साथ ओवरराइट कर रहे हैं Person.prototype। इसलिए यदि हम फोन करते हैं Student.prototype.constructor, तो Personइसके बजाय यह इंगित करेगा Studentयही कारण है कि हमें इसे ठीक करने की आवश्यकता है।

// 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 में, हमारी constructorसंपत्ति एक संदर्भ है जो एक फ़ंक्शन को संदर्भित करती है जिसे हमने 'कंस्ट्रक्टर' होने के इरादे से लिखा है। newकीवर्ड हमें क्या देता है, इसके अलावा , कंस्ट्रक्टर अन्यथा 'प्लेन' फंक्शन है।

ईएस 6 में, constructorअब हम कक्षाओं को लिखने के तरीके में बनाया गया है - जैसे कि, यह एक विधि के रूप में प्रदान किया जाता है जब हम एक वर्ग घोषित करते हैं। यह बस वाक्य रचना चीनी है, लेकिन superजब हम एक मौजूदा वर्ग का विस्तार कर रहे हैं, तो यह हमें कुछ उपयुक्तताओं तक पहुंच प्रदान करता है । तो हम उपरोक्त कोड इस तरह से लिखेंगे:

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 Studentलौट आया true। स्पष्टीकरण के लिए stackoverflow.com/questions/35537995/… देखें । यह भी जब आप कहते हैं which is, at the moment, nothingकि आप क्या कर रहे हैं? प्रत्येक फ़ंक्शन का एक प्रोटोटाइप होता है, इसलिए यदि मैं जांचता हूं Student.prototypeकि यह कुछ है।
एसेम बंसल

मेरी गलती। इसमें should एवे इंस्टाफॉफ पर्सन ’पढ़ना चाहिए था जो कि गलत होगा। मैं उस हिस्से में संशोधन करूंगा। आप सही हैं कि प्रत्येक फ़ंक्शन में एक प्रोटोटाइप गुण है। हालाँकि , प्रोटोटाइप को असाइन किए बिना Object.create(Person.prototype), Student.prototypeखाली है। इसलिए यदि हम लॉग इन करते हैं eve.species, तो यह अपने सुपरक्लास, व्यक्ति, और यह लॉग नहीं करेगा 'human'। संभवतया, हम चाहते हैं कि हर उपवर्ग इसके प्रोटोटाइप से विरासत में मिले और इसके सुपर प्रोटोटाइप भी।
ब्यूहमन

स्पष्ट करने के लिए, द्वारा which is, at the moment, nothing, मेरा मतलब था कि Student.prototypeवस्तु खाली है।
बेथुमन

प्रोटोटाइप पर अधिक: का काम बिना Student.prototypeकरने के लिए Object.create(Person.prototype)- जो है, यदि आप याद है, उसी तरह व्यक्ति के सभी उदाहरणों को सौंपने के लिए स्थापित कर रहे हैं Person.prototype- का एक उदाहरण पर एक संपत्ति को देख Studentप्रतिनिधि हैं केवल Student.prototype । तो eve.speciesइसके लुक को फेल कर देंगे। हम इसे असाइन करते हैं, करते हैं Student.prototypeतो खुद के प्रतिनिधियों Person.prototype, और को देख eve.speciesवापस आ जाएगी human
18

ऐसा लगता है कि यहां कुछ चीजें गलत हैं: "यह आवश्यक है जब आप 'सबक्लासिंग' का अनुकरण करने का प्रयास कर रहे हों [...] ताकि जब आप जांच लें कि क्या कोई उदाहरण instance'उपवर्ग' निर्माता है, तो यह सटीक होगा।" नहीं,instanceof उपयोग नहीं करता है constructor"हालांकि, अगर हम छात्र के .prototype.constructor को देखते हैं, तो यह अभी भी व्यक्ति को इंगित करेगा" नहीं, यह होगा Student। मुझे इस उदाहरण की बात समझ में नहीं आती। एक निर्माता में एक फ़ंक्शन को कॉल करना वंशानुक्रम नहीं है। "ES6 में, कंस्ट्रक्टर अब एक फ़ंक्शन के संदर्भ के बजाय एक वास्तविक फ़ंक्शन है" उह क्या?
फेलिक्स क्लिंग

10

मैं असहमत हूँ। प्रोटोटाइप सेट करना आवश्यक नहीं है। वही सटीक कोड लें, लेकिन प्रोटोटाइप को हटा दें। अवरोधक लाइन। क्या कुछ बदलता है? नहीं। अब, निम्नलिखित बदलाव करें:

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

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

और परीक्षण कोड के अंत में ...

alert(student1.favoriteColor);

रंग नीला होगा।

मेरे अनुभव में प्रोटोटाइप.कॉन्स्ट्रक्टर में एक बदलाव, बहुत कुछ नहीं करता है जब तक कि आप बहुत विशिष्ट, बहुत जटिल चीजें नहीं कर रहे हैं जो शायद वैसे भी अभ्यास नहीं हैं :)

संपादित करें: थोड़ी देर के लिए वेब पर घूमने और कुछ प्रयोग करने के बाद, ऐसा लग रहा है कि लोग कंस्ट्रक्टर को सेट कर रहे हैं ताकि यह 'नई' के साथ बनाई जा रही चीज की तरह दिखे। मुझे लगता है कि मैं तर्क दूंगा कि इसके साथ समस्या यह है कि जावास्क्रिप्ट एक प्रोटोटाइप भाषा है - विरासत जैसी कोई चीज नहीं है। लेकिन अधिकांश प्रोग्रामर प्रोग्रामिंग की पृष्ठभूमि से आते हैं जो विरासत को 'रास्ता' के रूप में धकेलते हैं। इसलिए हम इस प्रोटोटाइप भाषा को 'क्लासिक' भाषा बनाने के लिए सभी तरह की चीजों के साथ आते हैं .. जैसे कि 'कक्षाएं'। वास्तव में, उन्होंने जो उदाहरण दिया है, उसमें एक नया छात्र एक व्यक्ति है - यह किसी अन्य छात्र से 'विस्तारित' नहीं होता है ... छात्र व्यक्ति के बारे में सब कुछ है, और जो भी व्यक्ति छात्र है वह भी है। छात्र, और जो कुछ भी आप बढ़ाएँ

क्रॉकफोर्ड थोड़ा पागल और अति उत्साही है, लेकिन उसके द्वारा लिखे गए कुछ सामानों पर कुछ गंभीर रीडिंग करें .. यह आपको इस सामान को बहुत अलग तरीके से देखेगा।


8
यह प्रोटोटाइप चेन को इनहेरिट नहीं करता है।
साइरफ

1
@ चार साल बाद बातचीत में धीरे-धीरे क्लैप का स्वागत। हाँ, प्रोटोटाइप श्रृंखला विरासत में मिली है, चाहे आप प्रोटोटाइप को ओवरराइट करें। इसका परीक्षण करके देखें।
स्टीफन

7
आपको वह कोड याद आ रहा है जो प्रोटोटाइप को इनहेरिट करता है। इंटरनेट पर आपका स्वागत है।
साइपर

1
@Cypher कोड स्निपेट लिंक किए गए लेख में कोड पर आधारित था। प्रश्न को संपूर्णता में पढ़ने के लिए आपका स्वागत है। ओह। रुको।
स्टीफन

1
@ मैचर का मतलब था कि यह शास्त्रीय विरासत है। मेरी ओर से वर का खराब विकल्प।
स्टीफन

9

यह बहुत बड़ा नुकसान है कि अगर आपने लिखा है

Student.prototype.constructor = Student;

लेकिन तब अगर कोई शिक्षक था जिसका प्रोटोटाइप भी व्यक्ति था और आपने लिखा था

Teacher.prototype.constructor = Teacher;

तब छात्र कंस्ट्रक्टर अब शिक्षक है!

संपादित करें: आप यह सुनिश्चित करके इससे बच सकते हैं कि आपने मोज़िला उदाहरण के रूप में, Object.create का उपयोग करके बनाए गए व्यक्ति वर्ग के नए उदाहरणों का उपयोग करके छात्र और शिक्षक प्रोटोटाइप सेट किए थे।

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

1
Student.prototype = Object.create(...)इस प्रश्न में माना जाता है। यह उत्तर और कुछ नहीं बल्कि संभावित भ्रम को जोड़ता है।
एंड्रे शैलेला

3
@ AndréNeves मुझे यह उत्तर मददगार लगा। Object.create(...)एमडीएन लेख में उपयोग किया जाता है जो प्रश्न को जन्म देता है, लेकिन प्रश्न में ही नहीं। मुझे यकीन है कि बहुत से लोग क्लिक नहीं करते हैं।
एलेक्स रोस

प्रश्न में दिए गए लिंक किए गए लिंक से जुड़े लेख का उपयोग Object.create () में किया गया है। यह उत्तर और संपादित करें ओ.टी. उत्तर वास्तव में प्रासंगिक नहीं हैं, और यह कम से कम कहने के लिए भ्रामक है :-)
Drenai

1
व्यापक बिंदु यह है कि ऐसे गोच हैं जो लोगों को जावास्क्रिप्ट प्रोटोटाइप के लिए नया रूप देंगे। यदि हम 2016 में चर्चा कर रहे हैं, तो आपको वास्तव में ES6 वर्गों, बैबेल और / या टाइपस्क्रिप्ट का उपयोग करना चाहिए। लेकिन अगर आप वास्तव में इस तरह से कक्षाओं का निर्माण करना चाहते हैं, तो यह समझने में मदद करता है कि प्रोटोटाइप चेन वास्तव में अपनी शक्ति का लाभ उठाने के लिए कैसे काम करते हैं। आप प्रोटोटाइप के रूप में किसी भी ऑब्जेक्ट का उपयोग कर सकते हैं, और शायद आप एक अलग ऑब्जेक्ट को नया नहीं करना चाहते हैं। इसके अलावा, HTML 5 के पूरी तरह से व्यापक होने से पहले, Object.create हमेशा उपलब्ध नहीं था, इसलिए गलत तरीके से क्लास सेट करना आसान था।
जेम्स डी

5

अभी तक भ्रम की स्थिति बनी हुई है।

मूल उदाहरण के बाद, जैसा कि आपके पास एक मौजूदा वस्तु student1है:

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

मान लीजिए कि आप यह नहीं जानना चाहते कि कैसे student1बनाया जाता है, तो आप इसे पसंद करना चाहते हैं, आप इसकी तरह की संपत्ति का उपयोग कर सकते हैं student1:

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

Studentयदि यह निर्माण संपत्ति सेट नहीं है, तो यहां से गुण प्राप्त करने में विफल हो जाएगा । बल्कि यह एक Personवस्तु का निर्माण करेगा ।


2

एक अच्छा कोड उदाहरण दिया गया है कि प्रोटोटाइप निर्माता को सेट करना वास्तव में क्यों आवश्यक है ..

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 ???? 
*/

आपका createNewCarतरीका कारखानों का निर्माण कर रहा है !? इसके अलावा ऐसा लगता है कि इसका var audiFactory = new CarFactory("Audi")उपयोग विरासत के उपयोग के बजाय किया जाना चाहिए था।
बेर्गी

आपका उदाहरण this.constructorआंतरिक रूप से उपयोग कर रहा है , इसलिए इसे सेट करना आश्चर्यजनक नहीं है। क्या आपके पास इसके बिना कोई उदाहरण है?
दिमित्री जैतसेव

1

इन दिनों शक्कर वाले फंक्शन 'क्लासेस' या 'न्यू' के इस्तेमाल की कोई ज़रूरत नहीं है। ऑब्जेक्ट शाब्दिक का उपयोग करें।

ऑब्जेक्ट प्रोटोटाइप पहले से ही एक 'क्लास' है। जब आप किसी ऑब्जेक्ट को शाब्दिक रूप से परिभाषित करते हैं, तो यह पहले से ही प्रोटोटाइप ऑब्जेक्ट का एक उदाहरण है। ये किसी अन्य ऑब्जेक्ट के प्रोटोटाइप आदि के रूप में भी कार्य कर सकते हैं।

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]

यह पढ़ने लायक है :

कक्षा-आधारित ऑब्जेक्ट-ओरिएंटेड भाषाएँ, जैसे कि जावा और C ++, दो अलग-अलग संस्थाओं की अवधारणा पर स्थापित होती हैं: कक्षाएं और उदाहरण।

...

एक प्रोटोटाइप-आधारित भाषा, जैसे कि जावास्क्रिप्ट, यह भेद नहीं करता है: इसमें बस ऑब्जेक्ट हैं। एक प्रोटोटाइप-आधारित भाषा में एक प्रोटोटाइप ऑब्जेक्ट की धारणा है, एक टेम्प्लेट के रूप में उपयोग की जाने वाली वस्तु जिसमें से एक नई वस्तु के लिए प्रारंभिक गुण प्राप्त होते हैं। कोई भी वस्तु अपने गुणों को निर्दिष्ट कर सकती है, या तो जब आप इसे बनाते हैं या रन टाइम पर। इसके अलावा, किसी भी वस्तु को किसी अन्य वस्तु के प्रोटोटाइप के रूप में जोड़ा जा सकता है, जिससे दूसरी वस्तु पहली वस्तु के गुणों को साझा कर सकती है


1

यह आवश्यक है जब आपको toStringबिना किसी बंदरबांट के विकल्प की आवश्यकता हो :

//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"]);


इसका क्या करना है? foo.constructor()??
Ry-

0

EDIT, मैं वास्तव में गलत था। बाहर लाइन टिप्पणी यह ​​व्यवहार बिल्कुल नहीं बदलता है। (मैंने इसका परीक्षण किया)


हाँ, यह आवश्यक है। जब तुम करोगे

Student.prototype = new Person();  

Student.prototype.constructorबन जाता है Person। इसलिए, कॉलिंग Student()द्वारा बनाई गई एक वस्तु लौटाएगा Person। अगर आप करते हैं तो

Student.prototype.constructor = Student; 

Student.prototype.constructorको वापस रीसेट किया गया है Student। अब जब आप Student()इसे निष्पादित करते हैं Student, जो मूल निर्माता को कॉल करता है Parent(), तो यह सही ढंग से विरासत में मिली वस्तु लौटाता है। यदि आप इसे Student.prototype.constructorकॉल करने से पहले रीसेट नहीं करते हैं, तो आपको एक ऐसी वस्तु मिलेगी, जिसमें कोई भी गुण सेट नहीं होगा Student()


3
प्रोटोटाइप निर्माण एक व्यक्ति बन सकता है, लेकिन यह उचित है क्योंकि यह व्यक्ति से सभी गुणों और विधियों को विरासत में मिला है। प्रोटोटाइप को स्थापित किए बिना एक नया छात्र () बनाना। निर्माणकर्ता उचित रूप से अपने स्वयं के निर्माता को कॉल करता है।
स्टीफन

0

दिए गए सरल निर्माण कार्य:

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(){...}

डिफ़ॉल्ट रूप से (विनिर्देशन से https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor ) से, सभी प्रोटोटाइपों को स्वचालित रूप से एक निर्माता मिलता है जिसे निर्माता कहा जाता है जो फ़ंक्शन पर वापस इंगित करता है। यह एक संपत्ति है। कंस्ट्रक्टर के आधार पर, अन्य गुणों और विधियों को प्रोटोटाइप में जोड़ा जा सकता है जो बहुत सामान्य अभ्यास नहीं है, लेकिन फिर भी इसे एक्सटेंशन के लिए अनुमति दी जाती है।

तो बस जवाब देना: हमें यह सुनिश्चित करने की आवश्यकता है कि प्रोटोटाइप में मूल्य। अवरोधक सही ढंग से सेट है जैसा कि विनिर्देश द्वारा माना जाता है।

क्या हमें हमेशा इस मूल्य को सही ढंग से निर्धारित करना है? यह डिबगिंग के साथ मदद करता है और विनिर्देश के खिलाफ आंतरिक संरचना को सुसंगत बनाता है। हमें निश्चित रूप से तब होना चाहिए जब हमारे एपीआई का उपयोग तीसरे पक्ष द्वारा किया जा रहा है, लेकिन वास्तव में नहीं जब कोड को रनटाइम में निष्पादित किया जाता है।


0

यहाँ MDN से एक उदाहरण है जो मुझे इसके उपयोग को समझने में बहुत मददगार लगा।

जावास्क्रिप्ट में, हम है async functionsजो रिटर्न AsyncFunction वस्तु। AsyncFunctionएक वैश्विक वस्तु नहीं है, लेकिन कोई इसे constructorसंपत्ति का उपयोग करके प्राप्त कर सकता है और इसका उपयोग कर सकता है।

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

यह आवश्यक नहीं है। यह कई चीजों में से एक है जो पारंपरिक है, ओओपी चैंपियन जावास्क्रिप्ट की प्रोटोटाइप विरासत को शास्त्रीय विरासत में बदलने की कोशिश करते हैं। केवल एक चीज जो निम्नलिखित है

Student.prototype.constructor = Student; 

करता है, कि अब आपके पास वर्तमान "कंस्ट्रक्टर" का संदर्भ है।

वेन के उत्तर में, जिसे सही के रूप में चिह्नित किया गया है, आप ठीक वही काम कर सकते हैं जो निम्न कोड करता है

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

नीचे दिए गए कोड के साथ (बस इसे बदलें। व्यक्ति के साथ संपर्क करें)

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

ईश्वर का शुक्र है कि ES6 क्लासिकल इनहेरिटेंस शुद्धतावादियों के साथ क्लास, एक्सटेंड्स और सुपर जैसे लैंग्वेज के ओरिजिनल ऑपरेटर्स का इस्तेमाल कर सकते हैं और हमें प्रोटोटाइप.कॉन्स्ट्रक्टर करेक्शंस और पेरेंट रेफ़रोल्स की तरह नहीं देखना है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.