जावास्क्रिप्ट कैसे काम करता है।


2041

मैं गतिशील प्रोग्रामिंग भाषाओं में नहीं हूं, लेकिन मैंने जावास्क्रिप्ट कोड का अपना उचित हिस्सा लिखा है। मुझे वास्तव में इस प्रोटोटाइप-आधारित प्रोग्रामिंग के आसपास अपना सिर नहीं मिला, क्या कोई जानता है कि यह कैसे काम करता है?

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

मुझे याद है कि थोड़ी देर पहले मैंने लोगों के साथ एक बहुत चर्चा की थी (मुझे यकीन नहीं है कि मैं क्या कर रहा हूं) लेकिन जैसा कि मैं इसे समझता हूं, एक वर्ग की कोई अवधारणा नहीं है। यह सिर्फ एक वस्तु है, और उन वस्तुओं के उदाहरण मूल, सही के क्लोन हैं?

लेकिन जावास्क्रिप्ट में इस ".prototype" संपत्ति का सटीक उद्देश्य क्या है? यह तात्कालिक वस्तुओं से कैसे संबंधित है?

अपडेट: सही तरीका

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

साथ ही इन स्लाइड्स ने वास्तव में बहुत मदद की।


78
जॉन रेसिग के फंक्शन प्रोटोटाइप्स पर कुछ स्लाइड्स हैं जो विषय को देखते समय मेरे लिए मददगार थे (आप कोड में बदलाव भी कर सकते हैं और देख सकते हैं कि क्या होता है ...) http://ejohn.org/apps/learn/#64
जॉन फोस्टर

5
महान संदर्भ सामग्री, इस सवाल को जानकारीपूर्ण रखने के प्रयोजनों के लिए शायद जॉन की साइट से कुछ टिप्पणियों को आपके उत्तर पर रखें यदि आपकी साइट इस तरह से बदलती है कि आपका लिंक अब उपलब्ध नहीं है। किसी भी तरह से +1, ने मेरी मदद की।
क्रिस

95
जॉन रेसिग के जावास्क्रिप्ट निनजा स्लाइड # 64 के लिए आपके लिंक के लिए +1 । वहाँ से शुरू करना वास्तव में सहायक था, और मुझे ऐसा लगता है कि मैं प्रोटोटाइप को सही ढंग से समझता हूं।
एक भुगतान किया बेवकूफ

4
क्या हमें वास्तव में प्रोटोटाइप लगाने के लिए एक कार्यात्मक वस्तु की आवश्यकता है? यदि हाँ तो क्यों?
अंशुल

6
यह आपकी मदद कर सकता है: webdeveasy.com/javascript-prototype
Naor

जवाबों:


1007

प्रत्येक जावास्क्रिप्ट ऑब्जेक्ट में एक आंतरिक "स्लॉट" होता है, [[Prototype]]जिसका मूल्य nullया तो होता है या ए object। आप एक ऑब्जेक्ट पर एक संपत्ति के रूप में एक स्लॉट के बारे में सोच सकते हैं, जो आपके द्वारा लिखे गए कोड से छिपा हुआ जावास्क्रिप्ट इंजन के लिए आंतरिक है। चारों ओर चौकोर कोष्ठक [[Prototype]]जानबूझकर हैं, और आंतरिक स्लॉट्स को निरूपित करने के लिए एक ECMAScript विनिर्देशन सम्मेलन हैं।

[[Prototype]]किसी वस्तु द्वारा इंगित किया गया मान , बोलचाल की भाषा में "उस वस्तु का प्रोटोटाइप" के रूप में जाना जाता है।

यदि आप डॉट ( obj.propName) या ब्रैकेट ( obj['propName']) संकेतन के माध्यम से किसी संपत्ति तक पहुंचते हैं, और ऑब्जेक्ट में सीधे ऐसी संपत्ति नहीं होती है (यानी , खुद की संपत्ति , चेक के माध्यम से obj.hasOwnProperty('propName')), रनटाइम ऑब्जेक्ट पर संदर्भित नाम के साथ एक संपत्ति की तलाश करता है। द्वारा [[Prototype]]बजाय। यदि संपत्ति में [[Prototype]] भी ऐसी कोई संपत्ति नहीं [[Prototype]]है, तो बदले में इसकी जाँच की जाती है। इस तरह, मूल वस्तु के प्रोटोटाइप श्रृंखला को एक मैच मिलने तक या उसके अंत तक पहुंचने तक चलाया जाता है। प्रोटोटाइप श्रृंखला के शीर्ष पर nullमूल्य है।

आधुनिक जावास्क्रिप्ट कार्यान्वयन [[Prototype]]निम्नलिखित तरीकों से पढ़ने और / या लिखने की अनुमति देते हैं :

  1. newऑपरेटर (कॉन्फ़िगर एक निर्माता समारोह से लौट आए डिफ़ॉल्ट वस्तु पर प्रोटोटाइप श्रृंखला),
  2. extendsकीवर्ड (जब वर्ग सिंटैक्स का उपयोग प्रोटोटाइप श्रृंखला कॉन्फ़िगर करता है),
  3. Object.create[[Prototype]]परिणामी वस्तु के रूप में आपूर्ति किए गए तर्क को सेट करेगा ,
  4. Object.getPrototypeOfऔर Object.setPrototypeOf(प्राप्त / सेट के [[Prototype]] बाद वस्तु निर्माण), और
  5. मानकीकृत अभिग्रहणकर्ता (जैसे। गटर / सेटर) नाम की संपत्ति __proto__(4. के समान)

Object.getPrototypeOfऔर Object.setPrototypeOfअधिक पसंद कर रहे हैं __proto__, भाग में, क्योंकि के व्यवहार o.__proto__ असामान्य है एक वस्तु का एक प्रोटोटाइप है जब null

ऑब्जेक्ट का [[Prototype]]निर्माण शुरू में ऑब्जेक्ट निर्माण के दौरान किया जाता है।

यदि आप एक नई वस्तु बनाते हैं new Func(), तो वस्तु की [[Prototype]]इच्छा, डिफ़ॉल्ट रूप से, द्वारा संदर्भित वस्तु पर सेट की जाएगी Func.prototype

ध्यान दें, इसलिए, सभी वर्गों, और सभी फ़ंक्शन जो newऑपरेटर के साथ उपयोग किए जा सकते हैं , .prototypeउनके पास अपने स्वयं के [[Prototype]]आंतरिक स्लॉट के अलावा एक संपत्ति है । "प्रोटोटाइप" शब्द का यह दोहरा उपयोग भाषा में नए लोगों के बीच अंतहीन भ्रम का स्रोत है।

newनिर्माण कार्यों के साथ उपयोग करने से हमें जावास्क्रिप्ट में शास्त्रीय विरासत का अनुकरण करने की अनुमति मिलती है; यद्यपि जावास्क्रिप्ट की विरासत प्रणाली है - जैसा कि हमने देखा है - प्रोटोटाइप, और वर्ग-आधारित नहीं।

जावास्क्रिप्ट में वर्ग सिंटैक्स की शुरूआत से पहले, निर्माण कार्य कक्षाओं को अनुकरण करने का एकमात्र तरीका था। हम .prototypeसाझा किए गए सदस्यों के रूप में कंस्ट्रक्टर फ़ंक्शन की संपत्ति द्वारा संदर्भित ऑब्जेक्ट के गुणों के बारे में सोच सकते हैं; अर्थात। सदस्य जो प्रत्येक उदाहरण के लिए समान हैं। क्लास-आधारित सिस्टम में, तरीकों को प्रत्येक उदाहरण के लिए उसी तरह लागू किया जाता है, इसलिए तरीकों को .prototypeसंपत्ति में जोड़ा जाता है ; एक वस्तु के क्षेत्र, हालांकि, उदाहरण-विशिष्ट हैं और इसलिए निर्माण के दौरान ऑब्जेक्ट में ही जोड़ दिए जाते हैं।

वर्ग सिंटैक्स के बिना, डेवलपर्स को शास्त्रीय विरासत के समान कार्यक्षमता प्राप्त करने के लिए प्रोटोटाइप श्रृंखला को मैन्युअल रूप से कॉन्फ़िगर करना पड़ा। इसने इसे प्राप्त करने के लिए अलग-अलग तरीकों को अपनाया।

यहाँ एक तरीका है:

function Child() {}
function Parent() {}
Parent.prototype.inheritedMethod = function () { return 'this is inherited' }

function inherit(child, parent) {
  child.prototype = Object.create(parent.prototype)
  child.prototype.constructor = child
  return child;
}

Child = inherit(Child, Parent)
const o = new Child
console.log(o.inheritedMethod()) // 'this is inherited'

... और यहाँ एक और तरीका है:

function Child() {}
function Parent() {}
Parent.prototype.inheritedMethod = function () { return 'this is inherited' }

function inherit(child, parent) {
    function tmp() {}
    tmp.prototype = parent.prototype
    const proto = new tmp()
    proto.constructor = child
    child.prototype = proto
    return child
}

Child = inherit(Child, Parent)
const o = new Child
console.log(o.inheritedMethod()) // 'this is inherited'

ES2015 में पेश किया गया क्लास सिंटैक्स extendsजावास्क्रिप्ट में शास्त्रीय विरासत को अनुकरण करने के लिए प्रोटोटाइप श्रृंखला को कॉन्फ़िगर करने के लिए "एक सही तरीका" के रूप में प्रदान करके चीजों को सरल करता है।

तो, ऊपर दिए गए कोड के समान, यदि आप नई वस्तु बनाने के लिए वर्ग सिंटैक्स का उपयोग करते हैं जैसे:

class Parent { inheritedMethod() { return 'this is inherited' } }
class Child extends Parent {}

const o = new Child
console.log(o.inheritedMethod()) // 'this is inherited'

... परिणामी वस्तु [[Prototype]]को एक उदाहरण के लिए सेट किया जाएगा Parent, जिसका [[Prototype]], बदले में, है Parent.prototype

अंत में, यदि आप के माध्यम से एक नई वस्तु बनाते हैं Object.create(foo), तो परिणामस्वरूप वस्तु [[Prototype]]को सेट किया जाएगा foo


1
तो, मैं अपनी छोटी स्निपेट में प्रोटोटाइप संपत्ति पर नई संपत्तियों को परिभाषित करके कुछ गलत कर रहा हूं?
जॉन लेडग्रेन

3
मुझे लगता है कि प्रथम श्रेणी के नागरिकों के रूप में फ़ंक्शन ऑब्जेक्ट्स का अर्थ है।
जॉन लेडिग्रेन

8
मुझे गैर मानक चीजों से नफरत है, विशेष रूप से प्रोग्रामिंग भाषाओं में, जब कोई स्पष्ट रूप से इसकी आवश्यकता नहीं है तो एक प्रोटो भी क्यों है ?
जॉन लेडिग्रेन

1
जेएस दुभाषिया द्वारा आंतरिक उपयोग के लिए @ जॉन __proto__ की आवश्यकता है। प्रत्येक ऑब्जेक्ट को यह जानना होगा कि कौन से गुण और विधियाँ प्रोटोटाइप का एक हिस्सा हैं और जो ऑब्जेक्ट का ही एक हिस्सा हैं। JS दुभाषिया को किसी ऑब्जेक्ट पर प्रोटोटाइप किए गए तरीकों को कॉल करने में सक्षम होना चाहिए।
बीएमनर

17
ध्यान दें कि [[प्रोटोटाइप]] का उपयोग जानबूझकर किया गया है - ECMA-२६२ डबल वर्ग कोष्ठक के साथ आंतरिक गुणों के नामों को संलग्न करता है
क्रिस्टोफ़

1798

जावा, सी # या सी ++ जैसी शास्त्रीय विरासत को लागू करने वाली भाषा में - आप एक वर्ग बनाकर शुरू करते हैं - अपनी वस्तुओं के लिए एक खाका - और फिर आप उस वर्ग से नई वस्तुएं बना सकते हैं या आप वर्ग का विस्तार कर सकते हैं, एक नई कक्षा को परिभाषित कर सकते हैं जो वृद्धि करता है मूल वर्ग।

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

उदाहरण:

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

अब तक मैं आधार वस्तु का विस्तार करता रहा हूं, अब मैं एक अन्य वस्तु बनाता हूं और फिर व्यक्ति से विरासत में प्राप्त करता हूं।

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

जैसा कि मैंने कहा कि मैं सेटअमाउंटड्यू (), गेटअमाउंटड्यू () को एक व्यक्ति पर कॉल नहीं कर सकता।

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

352
मुझे लगता है कि स्टैकओवरफ़्लो पर जवाब न केवल मूल पोस्टर के लिए दिलचस्प हैं, बल्कि अन्य लोगों के एक बड़े समुदाय के लिए भी हैं जो गुप्त या खोज से आ रहे हैं। और मैं उनमें से एक रहा हूं और मुझे पुराने पदों से लाभ हुआ है। मुझे लगता है कि मैं कुछ कोड उदाहरण जोड़कर अन्य उत्तरों में योगदान कर सकता हूं। आपके प्रश्न के बारे में: यदि आप नया छोड़ते हैं, तो यह काम नहीं करता है। जब मैं myCustomer.sayMyName कहता हूं () यह "myCustomer.sayMyName एक फ़ंक्शन नहीं है" देता है। सबसे आसान तरीका है फायरबग के साथ प्रयोग और देखें कि क्या होता है।
stivlo

7
जहाँ तक मैं var Person = function (नाम) {...} समझता हूँ; व्यक्तिगत वस्तुओं के निर्माण में सक्षम एक निर्माण कार्य को परिभाषित कर रहा है। इसलिए अभी तक कोई वस्तु नहीं है, केवल अनाम निर्माण कार्य व्यक्ति को सौंपा गया है। यह एक बहुत अच्छी व्याख्या है: helephant.com/2008/08/how-javascript-objects-work
stivlo

17
चेतावनी: यह उत्तर इस तथ्य की उपेक्षा करता है कि मूल वर्ग के निर्माणकर्ता को प्रति उदाहरण के आधार पर नहीं बुलाया जाता है। एकमात्र कारण यह काम करता है क्योंकि उन्होंने बच्चे और माता-पिता दोनों के निर्माण में सटीक एक ही चीज़ (नाम की स्थापना) की थी। जावास्क्रिप्ट (और एक अंतिम समाधान) में वंशानुक्रम का प्रयास करते समय की गई सामान्य गलतियों पर अधिक गहराई से जानकारी के लिए, कृपया देखें: यह स्टैक ओवरफ्लो पोस्ट
ऐरेन कॉर्डोवा

3
मुझे लगता है कि इस उत्तर में यह भी उल्लेख नहीं है कि "नए व्यक्ति ()" को प्रोटोटाइप के रूप में उपयोग करके, आप वास्तव में "ग्राहक" की "संपत्ति" की "नाम" उदाहरण संपत्ति सेट कर रहे हैं ताकि "ग्राहक" (सभी ग्राहक) उदाहरणों में समान संपत्ति होगी)। हालांकि यह एक अच्छा बुनियादी उदाहरण है, यह मत करो। :) "Person.prototype" का प्रोटोटाइप सेट करके "पुल" के रूप में कार्य करने के लिए एक नया अनाम फ़ंक्शन बनाएं, फिर उससे एक उदाहरण बनाएं और इसके बजाय "Customer.prototype" को उस अनाम आवृत्ति पर सेट करें।
जेम्स विल्किंस

10
Customer.prototype = new Person();लाइन के बारे में , एमडीएन एक उदाहरण का उपयोग करके दिखाता है Customer.prototype = Object.create(Person.prototype), और बताता है कि 'यहां एक सामान्य त्रुटि "नए व्यक्ति ()" "का उपयोग करना हैsource
राफेल ईनग

186

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

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

कुछ महत्वपूर्ण बिंदु हैं जिन्हें हमें प्रोटोटाइप अवधारणा से गुजरने से पहले विचार करना होगा।

1- वास्तव में जावास्क्रिप्ट कैसे काम करता है:

पहला कदम उठाने के लिए हमें यह पता लगाना होगा कि वास्तव में जावास्क्रिप्ट कैसे कार्य करता है, एक वर्ग के रूप में कार्य करता है जैसे thisकि इसमें कीवर्ड का उपयोग करना या सिर्फ अपने तर्कों के साथ एक नियमित कार्य के रूप में, यह क्या करता है और क्या देता है।

मान लें कि हम Personऑब्जेक्ट मॉडल बनाना चाहते हैं । लेकिन इस चरण में मैं उपयोग prototypeऔर newकीवर्ड के बिना एक ही सटीक काम करने की कोशिश कर रहा हूं ।

तो इस चरण में functions, objectsऔर thisकीवर्ड, क्या हमारे पास सभी हैं।

पहला सवाल होगा कैसे thisकीवर्ड का उपयोग किए बिना उपयोगी हो सकता है newकीवर्ड

तो उत्तर देने के लिए कि मान लें कि हमारे पास एक खाली वस्तु है, और दो कार्य हैं:

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

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

और अब कीवर्ड के बिनाnew हम इन कार्यों का उपयोग कैसे कर सकते हैं। इसलिए जावास्क्रिप्ट के 3 अलग-अलग तरीके हैं:

ए। पहला तरीका केवल फ़ंक्शन को एक नियमित फ़ंक्शन के रूप में कॉल करना है:

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

इस मामले में, यह वर्तमान संदर्भ वस्तु होगी, जो आमतौर पर windowब्राउज़र या GLOBALमें वैश्विक वस्तु होती है Node.js। इसका अर्थ है कि हमारे पास Node.js में ब्राउजर या GLOBAL.name में window.name, "जॉर्ज" इसके मूल्य के रूप में होगा।

ख। हम उन्हें एक वस्तु से जोड़ सकते हैं , इसके गुणों के रूप में

- ऐसा करने का सबसे आसान तरीका खाली personवस्तु को संशोधित करना है , जैसे:

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

इस तरह हम उन्हें कॉल कर सकते हैं जैसे:

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

और अब personवस्तु की तरह है:

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

- किसी वस्तु को किसी संपत्ति में संलग्न करने का दूसरा तरीका उस वस्तु का उपयोग करना prototypeहै जिसे किसी भी जावास्क्रिप्ट वस्तु में पाया जा सकता है जिसका नाम है __proto__, और मैंने इसे सारांश भाग पर थोड़ा समझाने की कोशिश की है। इसलिए हम ऐसा करके ही परिणाम प्राप्त कर सकते हैं:

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

लेकिन इस तरह से जो हम वास्तव में कर रहे हैं वह संशोधित कर रहा है Object.prototype, क्योंकि जब भी हम शाब्दिक ( { ... }) का उपयोग करके एक जावास्क्रिप्ट ऑब्जेक्ट बनाते हैं , तो यह आधार पर बनाया जाता है Object.prototype, जिसका अर्थ है कि यह एक विशेषता नाम के रूप में नई बनाई गई वस्तु से जुड़ा हुआ है __proto__, इसलिए यदि हम इसे बदलते हैं , जैसा कि हमने अपने पिछले कोड स्निपेट पर किया है, सभी जावास्क्रिप्ट ऑब्जेक्ट बदल जाएंगे, एक अच्छा अभ्यास नहीं। तो अब बेहतर अभ्यास क्या हो सकता है:

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

और अब अन्य वस्तुएँ शांति में हैं, लेकिन यह अभी भी एक अच्छा अभ्यास नहीं लगता है। इसलिए हमारे पास अभी भी एक और समाधान है, लेकिन इस समाधान का उपयोग करने के लिए हमें उस कोड की उस पंक्ति पर वापस जाना चाहिए जहां personऑब्जेक्ट बनाया गया ( var person = {};) तब इसके लिए इसे निम्न करें:

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

यह क्या करता है एक नया जावास्क्रिप्ट बना रहा है Objectऔर विशेषता propertiesObjectको संलग्न करता है __proto__। तो यह सुनिश्चित करने के लिए कि आप क्या कर सकते हैं:

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

लेकिन यहां मुश्किल बिंदु यह है कि आपके पास ऑब्जेक्ट __proto__के पहले स्तर पर परिभाषित सभी गुणों तक पहुंच है person(अधिक विस्तार के लिए सारांश भाग पढ़ें)।


जैसा कि आप इन दो तरीकों में से किसी का उपयोग करते हुए देखते हैं, thisयह वास्तव में personऑब्जेक्ट को इंगित करेगा ।

सी। जावास्क्रिप्ट के पास फ़ंक्शन प्रदान करने का एक और तरीका है this, जो फ़ंक्शन का उपयोग करने के लिए कॉल या एप्लिकेशन का उपयोग कर रहा है।

लागू () विधि एक दिए गए इस मान और एक सरणी (या एक सरणी जैसी वस्तु) के रूप में दिए गए तर्कों के साथ एक फ़ंक्शन को कॉल करती है।

तथा

कॉल () विधि किसी दिए गए इस मान और व्यक्तिगत रूप से प्रदान किए गए तर्कों के साथ एक फ़ंक्शन को कॉल करती है।

इस तरह जो मेरा पसंदीदा है, हम आसानी से अपने कार्यों को कॉल कर सकते हैं जैसे:

Person.call(person, "George");

या

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

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

ये 3 विधियाँ .prototyp कार्यक्षमता का पता लगाने के लिए महत्वपूर्ण प्रारंभिक चरण हैं।


2- newकीवर्ड कैसे काम करता है?

.prototypeकार्यक्षमता को समझने के लिए यह दूसरा चरण है। इस प्रक्रिया का अनुकरण करने के लिए मैं इसका उपयोग करता हूं:

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

इस भाग में, मैं उन सभी चरणों को लेने की कोशिश कर रहा हूँ जो जावास्क्रिप्ट का उपयोग करता है, बिना newकीवर्ड का उपयोग किए और prototype, जब आप newकीवर्ड का उपयोग करते हैं । इसलिए जब हम कार्य करते हैं new Person("George"), तो Personफ़ंक्शन एक निर्माता के रूप में कार्य करता है, ये वही हैं जो जावास्क्रिप्ट करता है, एक-एक करके:

ए। सबसे पहले यह एक खाली वस्तु बनाता है, मूल रूप से एक खाली हैश जैसे:

var newObject = {};

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

हमारे my_person_prototypeयहाँ प्रोटोटाइप ऑब्जेक्ट के समान है।

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

यह तरीका नहीं है कि जावास्क्रिप्ट वास्तव में उन गुणों को संलग्न करता है जो प्रोटोटाइप में परिभाषित होते हैं। वास्तविक तरीका प्रोटोटाइप चेन अवधारणा से संबंधित है।


ए। और बी। इन दो चरणों के बजाय आप एक ही परिणाम कर सकते हैं:

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"

अब हम अपने में getNameफंक्शन को कॉल कर सकते हैं my_person_prototype:

newObject.getName();

सी। तब यह उस निर्माणकर्ता को वस्तु देता है,

हम अपने नमूने के साथ ऐसा कर सकते हैं:

Person.call(newObject, "George");

या

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

तब कंस्ट्रक्टर जो चाहे कर सकता है, क्योंकि यह उस कंस्ट्रक्टर के अंदर की वस्तु है जिसे अभी बनाया गया था।

अब अन्य चरणों का अनुकरण करने से पहले अंतिम परिणाम: ऑब्जेक्ट {नाम: "जॉर्ज"}


सारांश:

मूल रूप से, जब आप किसी फ़ंक्शन पर नए कीवर्ड का उपयोग करते हैं, तो आप उस पर कॉल कर रहे हैं और वह फ़ंक्शन एक निर्माता के रूप में कार्य करता है, इसलिए जब आप कहते हैं:

new FunctionName()

जावास्क्रिप्ट आंतरिक रूप से एक वस्तु बनाता है, एक खाली हैश और फिर वह उस वस्तु को कंस्ट्रक्टर को देता है, फिर कंस्ट्रक्टर जो चाहे वह कर सकता है, क्योंकि इस कंस्ट्रक्टर के अंदर वह वस्तु है जिसे अभी बनाया गया था और फिर यह आपको उस वस्तु को प्रदान करता है यदि आपने अपने फ़ंक्शन में रिटर्न स्टेटमेंट का उपयोग नहीं किया है या यदि आपने return undefined;अपने फ़ंक्शन बॉडी के अंत में रखा है ।

इसलिए जब जावास्क्रिप्ट किसी वस्तु पर एक संपत्ति को देखने जाता है, तो पहली चीज जो वह करता है, क्या वह उस वस्तु पर दिखता है। और फिर एक गुप्त संपत्ति है [[prototype]]जो हमारे पास आमतौर पर पसंद है __proto__और वह संपत्ति है जो जावास्क्रिप्ट अगले पर दिखती है। और जब वह इसके माध्यम से देखता है __proto__, जहां तक ​​यह फिर से एक और जावास्क्रिप्ट ऑब्जेक्ट है, इसकी अपनी __proto__विशेषता है, यह ऊपर और ऊपर जाता है जब तक कि यह उस बिंदु तक नहीं जाता है जहां अगला __proto__शून्य है। बिंदु जावास्क्रिप्ट में केवल उद्देश्य यह है कि इसकी है __proto__विशेषता मान शून्य होगा Object.prototypeवस्तु:

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

और यह है कि जावास्क्रिप्ट में वंशानुक्रम कैसे काम करता है।

प्रोटोटाइप श्रृंखला

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


6
a) कृपया संपत्तियों की नकल करके प्रोटोटाइप की व्याख्या न करें b) आंतरिक [[प्रोटोटाइप]] को सेट करने से पहले होता है कि कंस्ट्रक्टर फ़ंक्शन को उदाहरण पर लागू किया जाता है, कृपया यह बदलें कि आदेश c) jQuery इस प्रश्न में पूरी तरह से अपमानजनक है
Bergi

1
@ बर्गी: इशारा करने के लिए धन्यवाद, अगर आप मुझे बताएंगे कि अगर अब ठीक है, तो मुझे सराहना मिलेगी।
मेहरान हातिम

7
क्या आप इसे सरल बना सकते हैं? आप सभी बिंदुओं पर सही हैं, लेकिन इस विवरण को पढ़ने वाले छात्र पहली बार वास्तव में भ्रमित हो सकते हैं। किसी भी सरल उदाहरण को उठाएं, और कोड को स्वयं स्पष्ट करें या आप क्या मतलब है यह स्पष्ट करने के लिए टिप्पणियों का एक गुच्छा जोड़ें।
PM

2
@PM: आपकी प्रतिक्रिया के लिए धन्यवाद। मैंने इसे यथासंभव सरल बनाने की कोशिश की है, लेकिन मुझे लगता है कि आप सही हैं कि इसमें अभी भी कुछ अस्पष्ट बिंदु हैं। इसलिए मैं इसे संशोधित करने की कोशिश करूंगा और अधिक वर्णनात्मक भी हो सकता हूं। :)
मेहरान हाटामी

1
@AndreaMattioli क्योंकि इस तरह से आप एक पूरी तरह से नई वस्तु बना रहे हैं और पुराने को ओवरराइड कर रहे हैं जिसे अन्य वस्तुओं के बीच भी साझा किया जा सकता है। प्रतिस्थापित करने से __proto__आप पहले सभी शीर्ष स्तर के प्रोटोटाइप गुणों का सफाया कर देंगे और फिर आपके पास एक ताज़ा प्रोटो बेस होगा जिसे अब तक साझा नहीं किया गया है।
मेहरान हातिम

77

प्रोटोटाइप के सात Koans

जैसा कि सिरो सैन गहरे ध्यान के बाद माउंट फायर फॉक्स में उतरे, उनका मन स्पष्ट और शांतिपूर्ण था।

उनका हाथ हालांकि, बेचैन था, और खुद ही ब्रश पकड़कर नीचे दिए नोटों को दबा दिया।


0) दो अलग-अलग चीजों को "प्रोटोटाइप" कहा जा सकता है:

  • प्रोटोटाइप संपत्ति के रूप में, में obj.prototype

  • प्रोटोटाइप आंतरिक संपत्ति, ES5 के रूप [[Prototype]] में चिह्नित ।

    इसे ES5 के माध्यम से पुनः प्राप्त किया जा सकता है Object.getPrototypeOf()

    फ़ायरफ़ॉक्स __proto__संपत्ति के माध्यम से इसे विस्तार के रूप में सुलभ बनाता है । ES6 अब कुछ वैकल्पिक आवश्यकताओं का उल्लेख करता है__proto__


1) प्रश्न का उत्तर देने के लिए वे अवधारणाएँ मौजूद हैं:

जब मैं करता हूं obj.property, तो जेएस कहां दिखता है .property?

सहज रूप से, शास्त्रीय विरासत को संपत्ति की खोज को प्रभावित करना चाहिए।


2)

  • __proto__का उपयोग डॉट .प्रॉपर्टी लुकअप के लिए किया जाता है obj.property
  • .prototypeहै देखने के लिए सीधे, परोक्ष रूप के रूप में यह निर्धारित करता है प्रयोग किया जाता __proto__के साथ ऑब्जेक्ट निर्माण पर new

लुकअप क्रम है:

  • objगुणों के साथ जोड़ा obj.p = ...याObject.defineProperty(obj, ...)
  • के गुण obj.__proto__
  • obj.__proto__.__proto__और इतने पर के गुण
  • अगर कुछ __proto__है null, तो लौटें undefined

यह तथाकथित प्रोटोटाइप श्रृंखला है

आप के .साथ देखने से बच सकते हैं obj.hasOwnProperty('key')औरObject.getOwnPropertyNames(f)


3) सेट करने के दो मुख्य तरीके हैं obj.__proto__:

  • new:

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

    फिर newसेट किया है:

    f.__proto__ === F.prototype

    यह वह जगह है जहाँ इसका.prototype उपयोग किया जाता है।

  • Object.create:

     f = Object.create(proto)

    सेट:

    f.__proto__ === proto

4) कोड:

var F = function(i) { this.i = i }
var f = new F(1)

निम्नलिखित आरेख के अनुरूप (कुछ Numberसामान छोड़ा गया है):

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

यह आरेख कई भाषा पूर्वनिर्धारित वस्तु नोड्स दिखाता है:

  • null
  • Object
  • Object.prototype
  • Function
  • Function.prototype
  • 1
  • Number.prototype( (1).__proto__वाक्य रचना को संतुष्ट करने के लिए कोष्ठक अनिवार्य किया जा सकता है)

कोड की हमारी 2 पंक्तियों ने केवल निम्नलिखित नई वस्तुएँ बनाई:

  • f
  • F
  • F.prototype

ifजब आप करते हैं तो अब एक संपत्ति है:

var f = new F(1)

यह मूल्यांकन करता है Fसाथ thisमूल्य है कि किया जा रहा है newजो तब को सौंप दिया जाता है वापस आ जाएगी, f


5) .constructor आम तौर F.prototypeपर .देखने के माध्यम से आता है :

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

जब हम लिखते हैं f.constructor, तो जावास्क्रिप्ट .लुकअप करता है:

  • f नहीं है .constructor
  • f.__proto__ === F.prototypeहै .constructor === F, इसलिए इसे ले लो

परिणाम f.constructor == Fसहज रूप से सही है, क्योंकि Fइसका उपयोग निर्माण के लिए किया जाता है f, उदाहरण के लिए फ़ील्ड सेट करें, क्लासिक ओओपी भाषाओं में बहुत पसंद है।


6) प्रोटोटाइप श्रृंखलाओं में हेरफेर करके शास्त्रीय विरासत सिंटैक्स प्राप्त किया जा सकता है।

ईएस 6 classऔर extendsकीवर्ड जोड़ता है , जो पहले से संभव प्रोटोटाइप हेरफेर पागलपन के लिए ज्यादातर सिंटेक्स चीनी हैं।

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.
c = new C(1)
c.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

सभी पूर्वनिर्धारित वस्तुओं के बिना सरलीकृत आरेख:

(c)----->(1)
 |   i
 |
 |
 |[[Prototype]]
 |
 |
 v    __proto__
(C)<--------------(D)         (d)
| |                |           |
| |                |           |
| |prototype       |prototype  |[[Prototype]] 
| |                |           |
| |                |           |
| |                | +---------+
| |                | |
| |                | |
| |                v v
|[[Prototype]]    (D.prototype)--------> (inc2 function object)
| |                |             inc2
| |                |
| |                |[[Prototype]]
| |                |
| |                |
| | +--------------+
| | |
| | |
| v v
| (C.prototype)------->(inc function object)
|                inc
v
Function.prototype

आइए अध्ययन के लिए कुछ समय दें कि निम्नलिखित कैसे काम करता है:

c = new C(1)
c.inc() === 2

पहली पंक्ति सेट c.iकरने के लिए 1के रूप में में विस्तार से बताया "4)"।

दूसरी पंक्ति में, जब हम करते हैं:

c.inc()
  • .inc[[Prototype]]श्रृंखला के माध्यम से पाया जाता है : c-> C-> C.prototype->inc
  • जब हम जावास्क्रिप्ट में एक फ़ंक्शन कहते हैं X.Y(), तो जावास्क्रिप्ट स्वचालित रूप से फ़ंक्शन कॉल के अंदर thisबराबर करने के लिए सेट होता Xहै Y()!

ठीक वही तर्क भी बताते हैं d.incऔर d.inc2

यह लेख https://javascript.info/class#not-just-a-syntax-sugar में आगे classजाने योग्य प्रभावों का उल्लेख है । उनमें से कुछ classकीवर्ड के बिना प्राप्त नहीं हो सकते हैं (TODO check जो):


1
@tomasb धन्यवाद! "मुझे नहीं पता कि आपको यह कहां मिला है": मैंने कुछ गतिशील भाषाओं को देखने के बाद, मैंने देखा कि उनकी कक्षा प्रणाली के बारे में सबसे ज्यादा मायने रखता है कि .लुकअप कैसे काम करता है (और डेटा की कितनी प्रतियां बनाई गई हैं) । तो मैं उस बिंदु को समझने के लिए तैयार हूं। बाकी Google + ब्लॉग पोस्ट्स हैं + हाथ पर एक जेएस दुभाषिया। :)
सिरो सेंटिल्ली 冠状 C ill ill 法轮功 '

1
मुझे अभी भी इस बात की जानकारी नहीं है कि g.constructor === ऑब्जेक्ट क्यों है क्योंकि आपने कहा है कि "4) जब आप f = new F करते हैं, तो नया भी f.constructor = F" सेट करता है। क्या आप मुझे और समझा सकते हैं? वैसे भी यह सबसे अच्छा जवाब है जिसकी मुझे तलाश है। आपको बहुत - बहुत धन्यवाद!
nguyenngoc101

@ nguyenngoc101 धन्यवाद! यह sets f.constructor = Fहिस्सा गलत तरीके से गलत था और आगे के खंडों के साथ विरोधाभास था: प्रोटोटाइप श्रृंखला पर देखने के .constructorमाध्यम से पाया जाता है .। अब निश्चित कर दिया।
सिरो संतिली 冠状 病毒 iro i '' '

सभी चर्चा से जो मुझे मिलता है (शास्त्रीय विरासत से आया है) अगर मैं कंस्ट्रक्टर फ़ंक्शन बनाता हूं और नए ऑपरेटर का उपयोग करके इसका उदाहरण बनाने की कोशिश करता हूं तो मुझे केवल वे विधियां और गुण मिलेंगे जो प्रोटो ऑब्जेक्ट से जुड़े थे, इसलिए सभी विधि संलग्न करना आवश्यक है और प्रोटो ऑब्जेक्ट्स प्रोटो ऑब्जेक्ट के लिए यदि हम उत्तराधिकार प्राप्त करना चाहते हैं, तो मील सही?
ब्लैक हॉक

1
@CiroSantilli 刘晓波 死 事件 法轮功 don't मुझे नहीं लगता कि यह क्रोमियम में बग है। मुझे लगता है कि यह सिर्फ एक लक्षण है कि fप्रोटोटाइप Fकेवल निर्माण के समय से सेट किया गया है ; यह निर्माण होने के बाद किसी भी समय fपता नहीं होगा या देखभाल नहीं करेगा F.prototype
जॉन ग्लासमी

76

prototypeआपको कक्षाएं बनाने की अनुमति देता है। यदि आप उपयोग नहीं करते हैं prototypeतो यह स्थिर हो जाता है।

यहाँ एक छोटा उदाहरण है।

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

उपरोक्त मामले में, आपके पास स्थैतिक फ़ोकेशन कॉल परीक्षण है। इस फ़ंक्शन को केवल obj.test द्वारा एक्सेस किया जा सकता है जहां आप एक वर्ग होने के लिए obj की कल्पना कर सकते हैं।

जहाँ नीचे कोड में के रूप में

function obj()
{
}

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

ओब्ज एक ऐसा वर्ग बन गया है जिसे अब तत्काल बनाया जा सकता है। Obj के कई उदाहरण मौजूद हो सकते हैं और इन सभी में testकार्य होता है।

ऊपर मेरी समझ है। मैं इसे एक सामुदायिक विकी बना रहा हूं, इसलिए अगर मैं गलत हूं तो लोग मुझे सुधार सकते हैं।


13
-1: prototypeकंस्ट्रक्टर कार्यों की एक संपत्ति है, उदाहरण नहीं, यानी आपका कोड गलत है! शायद आप __proto__वस्तुओं की गैर-मानक संपत्ति का मतलब है , लेकिन यह एक अलग जानवर है ...
क्रिस्टोफ

@ क्रिसटोफ - इसे इंगित करने के लिए धन्यवाद। मैंने नमूना कोड अपडेट कर दिया है।
रमेश

3
इसके लिए बहुत कुछ है ... प्लस जावास्क्रिप्ट एक वर्ग-आधारित भाषा नहीं है - यह प्रोटोटाइप के माध्यम से विरासत से संबंधित है, आपको मतभेदों को अधिक विस्तार से कवर करने की आवश्यकता है!
जेम्स

5
मुझे लगता है कि यह जवाब थोड़ा भ्रामक है।
अर्मिन Cifuentes

हो सकता है कि इसका उत्तर 'भ्रामक' हो, लेकिन समझाता है कि किस प्रोटोटाइप का उपयोग किया जाता है और अब मेरे लिए यह सब स्पष्ट है, उन सभी 'जवाबों' के बाद सैकड़ों 'वोट' मिलते हैं। धन्यवाद।
एलेक्स

66

इस धागे को पढ़ने के बाद, मैं जावास्क्रिप्ट प्रोटोटाइप चेन के साथ भ्रमित महसूस करता हूं, फिर मुझे ये चार्ट मिले

http://iwiki.readthedocs.org/en/latest/javascript/js_core.html#inheritance * [[protytype]] * और <code> प्रोटोटाइप </ code> फ़ंक्शन ऑब्जेक्ट्स की संपत्ति

प्रोटोटाइप चेन द्वारा जावास्क्रिप्ट वंशानुक्रम दिखाने के लिए यह एक स्पष्ट चार्ट है

तथा

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

यह एक कोड और कई अच्छे चित्र के साथ एक उदाहरण है।

प्रोटोटाइप श्रृंखला अंततः Object.prototype पर वापस आती है।

प्रोटोटाइप श्रृंखला को तकनीकी रूप से तब तक बढ़ाया जा सकता है जब तक आप चाहें, प्रत्येक बार मूल वर्ग के ऑब्जेक्ट के बराबर उपवर्ग का प्रोटोटाइप सेट करके।

आशा है कि यह जावास्क्रिप्ट प्रोटोटाइप चेन को समझने में भी आपके लिए मददगार होगा।


क्या जावास्क्रिप्ट पर कई वंशानुक्रम होना संभव है?

क्या फू एक वस्तु शाब्दिक है या कार्य वस्तु है? यदि इसकी वस्तु शाब्दिक है, तो मेरा मानना ​​है कि Foo.prototype कंस्ट्रक्टर के माध्यम से फू को वापस इंगित नहीं करेगा।
मधुर आहूजा

@ user3376708 जावास्क्रिप्ट केवल एकल वंशानुक्रम ( स्रोत ) का समर्थन करता है
राफेल Eyng

@ Nuno_147 यह पहली बार में स्पष्ट नहीं है, लेकिन यदि आप लंबे समय तक देखते हैं तो आपको इसमें से कुछ मिल सकता है।
मार्सेलोकेर

3
क्या आप [[Prototype]]इसका मतलब बता सकते हैं ?
CodyBugstein

40

प्रत्येक वस्तु में एक आंतरिक गुण होता है, [[प्रोटोटाइप]] , इसे दूसरी वस्तु से जोड़ता है:

object [[Prototype]]  anotherObject

पारंपरिक जावास्क्रिप्ट में, लिंक की गई वस्तु prototypeएक फ़ंक्शन की संपत्ति है:

object [[Prototype]]  aFunction.prototype

कुछ वातावरण का पर्दाफाश [[प्रोटोटाइप]] के रूप में __proto__:

anObject.__proto__ === anotherObject

ऑब्जेक्ट बनाते समय आप [[प्रोटोटाइप]] लिंक बनाते हैं।

// (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

तो ये कथन समतुल्य हैं:

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

आप वास्तव Object.prototypeमें एक नए बयान में लिंक लक्ष्य ( ) नहीं देख सकते हैं ; इसके बजाय लक्ष्य निर्माता ( Object) द्वारा निहित है ।

याद है:

  • प्रत्येक वस्तु में एक लिंक होता है, [[प्रोटोटाइप]] , कभी-कभी __proto__ के रूप में उजागर होता है
  • प्रत्येक फ़ंक्शन के पास एक prototypeसंपत्ति होती है, शुरू में एक खाली वस्तु रखती है।
  • नए के साथ बनाई गई वस्तुओं prototypeको उनके निर्माता की संपत्ति से जोड़ा जाता है ।
  • यदि किसी फ़ंक्शन का उपयोग एक निर्माता के रूप में कभी नहीं किया जाता है, तो इसकी prototypeसंपत्ति अप्रयुक्त हो जाएगी।
  • यदि आपको एक निर्माता की आवश्यकता नहीं है, तो इसके बजाय Object.create का उपयोग करें new

1
संशोधन 5 ने कुछ उपयोगी जानकारी को हटा दिया, जिसमें Object.create () की जानकारी भी शामिल है। संशोधन 4 देखें ।
पेलेक

@Palec मुझे क्या जोड़ना चाहिए?
सैम

2
IMO कम से कम Object.create()डॉक्स , @sam का लिंक । लिंक __proto__और Object.prototypeअच्छा संवर्द्धन होगा। और मुझे आपके उदाहरण पसंद Object.create()आए कि कैसे प्रोटोटाइप निर्माणकर्ताओं के साथ काम करते हैं और , लेकिन वे संभवतः लंबे और कम प्रासंगिक भाग थे जिनसे आप छुटकारा चाहते थे।
पालेक

सभी चर्चा से जो मुझे मिलता है (शास्त्रीय विरासत से आया है) अगर मैं कंस्ट्रक्टर फ़ंक्शन बनाता हूं और नए ऑपरेटर का उपयोग करके इसका उदाहरण बनाने की कोशिश करता हूं तो मुझे केवल वे विधियां और गुण मिलेंगे जो प्रोटो ऑब्जेक्ट से जुड़े थे, इसलिए सभी विधि संलग्न करना आवश्यक है और प्रोटो ऑब्जेक्ट्स प्रोटो ऑब्जेक्ट के लिए यदि हम उत्तराधिकार प्राप्त करना चाहते हैं, तो मील सही?
काला हॉक

29

जावास्क्रिप्ट में सामान्य अर्थों में विरासत नहीं है, लेकिन इसकी प्रोटोटाइप श्रृंखला है।

प्रोटोटाइप श्रृंखला

यदि किसी ऑब्जेक्ट का सदस्य उस ऑब्जेक्ट में नहीं पाया जा सकता है जो इसे प्रोटोटाइप श्रृंखला में खोजता है। श्रृंखला में अन्य वस्तुएँ होती हैं। किसी दिए गए उदाहरण के प्रोटोटाइप को __proto__चर के साथ एक्सेस किया जा सकता है । प्रत्येक वस्तु में एक है, क्योंकि जावास्क्रिप्ट में कक्षाओं और उदाहरणों के बीच कोई अंतर नहीं है।

एक फ़ंक्शन / चर को प्रोटोटाइप में जोड़ने का लाभ यह है कि इसे केवल एक बार मेमोरी में होना चाहिए, प्रत्येक उदाहरण के लिए नहीं।

यह विरासत के लिए भी उपयोगी है, क्योंकि प्रोटोटाइप श्रृंखला में कई अन्य ऑब्जेक्ट शामिल हो सकते हैं।


1
FF और Chrome प्रोटो का समर्थन करते हैं , लेकिन IE और ओपेरा नहीं।
कुछ

जॉर्ज, कृपया एक नॉब के लिए स्पष्ट करें - "जावास्क्रिप्ट में कक्षाओं और उदाहरणों के बीच कोई अंतर नहीं है।" - क्या आप विस्तृत कर सकते हैं? यह कैसे काम करता है?
हामिश ग्रुबीजन

सभी चर्चा से जो मुझे मिलता है (शास्त्रीय विरासत से आया है) अगर मैं कंस्ट्रक्टर फ़ंक्शन बनाता हूं और नए ऑपरेटर का उपयोग करके इसका उदाहरण बनाने की कोशिश करता हूं तो मुझे केवल वे विधियां और गुण मिलेंगे जो प्रोटो ऑब्जेक्ट से जुड़े थे, इसलिए सभी विधि संलग्न करना आवश्यक है और प्रोटो ऑब्जेक्ट्स प्रोटो ऑब्जेक्ट के लिए यदि हम उत्तराधिकार प्राप्त करना चाहते हैं, तो मील सही?
काला हॉक

28

यह लेख लंबा है। लेकिन मुझे यकीन है कि यह जावास्क्रिप्ट वंशानुक्रम की "प्रोटोटाइप" प्रकृति के बारे में आपके अधिकांश प्रश्नों को स्पष्ट करेगा। और भी अधिक। कृपया पूरा लेख पढ़ें।

जावास्क्रिप्ट में मूल रूप से दो प्रकार के डेटा प्रकार होते हैं

  • गैर वस्तु
  • वस्तुओं

गैर वस्तु

निम्नलिखित गैर वस्तु डेटा प्रकार हैं

  • तार
  • संख्या (NaN और इन्फिनिटी सहित)
  • बूलियन मान (सत्य, असत्य)
  • अपरिभाषित

जब आप टाइपोफ़ ऑपरेटर का उपयोग करते हैं तो ये डेटा प्रकार वापस लौट आते हैं

टाइपोफ़ "स्ट्रिंग शाब्दिक" (या स्ट्रिंग शाब्दिक युक्त एक चर) === 'स्ट्रिंग'

टाइप 5 (या कोई संख्यात्मक शाब्दिक या संख्यात्मक शाब्दिक या NaN या अनंत वाला एक चर ) === 'संख्या'

टाइपो ट्रू (या गलत या सही या गलत वाला चर ) === 'बूलियन'

typeof अपरिभाषित (या एक अपरिभाषित चर या एक चर युक्त अपरिभाषित ) === 'अपरिभाषित'

स्ट्रिंग , संख्या और बूलियन डेटा प्रकार दोनों के रूप में प्रतिनिधित्व किया जा सकता है वस्तुओं और गैर वस्तुओं .जब वे के रूप में वस्तुओं उनके typeof हमेशा === "वस्तु 'है प्रतिनिधित्व कर रहे हैं। एक बार जब हम ऑब्जेक्ट डेटा प्रकारों को समझ लेंगे तो हम इस पर वापस आ जाएंगे।

वस्तुओं

ऑब्जेक्ट डेटाटाइप्स को आगे दो प्रकारों में विभाजित किया जा सकता है

  1. प्रकार्य वस्तु
  2. नॉन फंक्शन टाइप ऑब्जेक्ट्स

समारोह प्रकार वस्तुओं जो कि स्ट्रिंग लौटाने हैं 'समारोह' के साथ typeof ऑपरेटर। सभी उपयोगकर्ता परिभाषित फ़ंक्शंस और ऑब्जेक्ट में निर्मित सभी जावास्क्रिप्ट जो नए ऑपरेटर का उपयोग करके नए ऑब्जेक्ट बना सकते हैं, इस श्रेणी में आते हैं। उदाहरण के लिए।

  • वस्तु
  • तार
  • संख्या
  • बूलियन
  • सरणी
  • टाइप किए गए एरे
  • रेगुलर एक्सप्रेशन
  • समारोह
  • अन्य सभी ऑब्जेक्ट्स में निर्मित जो नए ऑपरेटर का उपयोग करके नई ऑब्जेक्ट बना सकते हैं
  • फ़ंक्शन UserDefinedFunction () {/ * उपयोगकर्ता परिभाषित कोड * /}

तो, टाइपोफ़ (ऑब्जेक्ट) === टाइपोफ़ (स्ट्रिंग) === टाइपोफ़ (संख्या) === टाइपोफ़ (बुलियन) === टाइपोफ़ (एरे) === टाइपोफ़ (RegExp) === टाइपोफ़ (फ़ंक्शन) == = टाइपोफ (यूजरडिफाइंडफंक्शन) === 'फंक्शन'

सभी फंक्शन टाइप ऑब्जेक्ट वास्तव में जावास्क्रिप्ट ऑब्जेक्ट फंक्शन में निर्मित होते हैं ( फंक्शन ऑब्जेक्ट सहित अर्थात इसे पुनरावर्ती रूप से परिभाषित किया गया है)। यह ऐसा है जैसे कि इन वस्तुओं को निम्नलिखित तरीके से परिभाषित किया गया है

var Object= new Function ([native code for object Object])
var String= new Function ([native code for object String])
var Number= new Function ([native code for object Number])
var Boolean= new Function ([native code for object Boolean])
var Array= new Function ([native code for object Array])
var RegExp= new Function ([native code for object RegExp])
var Function= new Function ([native code  for object Function])
var UserDefinedFunction= new Function ("user defined code")

जैसा कि उल्लेख किया गया है, फ़ंक्शन प्रकार ऑब्जेक्ट्स नए ऑपरेटर का उपयोग करके नई ऑब्जेक्ट बना सकते हैं । प्रकार का ऑब्जेक्ट उदाहरण के लिए वस्तु , स्ट्रिंग , संख्या , बूलियन , सरणी , रेगुलर एक्सप्रेशन या UserDefinedFunction का उपयोग करके बनाया जा सकता है

var a=new Object() or var a=Object() or var a={} //Create object of type Object
var a=new String() //Create object of type String
var a=new Number() //Create object of type Number
var a=new Boolean() //Create object of type Boolean
var a=new Array() or var a=Array() or var a=[]  //Create object of type Array
var a=new RegExp() or var a=RegExp() //Create object of type RegExp
var a=new UserDefinedFunction() 

इस प्रकार बनाई गई वस्तुएँ सभी नॉन फंक्शन टाइप की वस्तुएँ होती हैं और अपनी टाइपोफ़ === 'ऑब्जेक्ट' को लौटाती हैं । इन सभी मामलों में ऑब्जेक्ट "a" ऑपरेटर को नया प्रयोग करके ऑब्जेक्ट नहीं बना सकता है। तो निम्नलिखित गलत है

var b=new a() //error. a is not typeof==='function'

वस्तु में बनाया मठ है typeof === 'वस्तु' । इसलिए नए ऑपरेटर द्वारा मैथ का नया ऑब्जेक्ट नहीं बनाया जा सकता है।

var b=new Math() //error. Math is not typeof==='function'

यह भी ध्यान दें कि ऑब्जेक्ट , एरे और रेगएक्सप फ़ंक्शंस ऑपरेटर नई का उपयोग किए बिना भी एक नई ऑब्जेक्ट बना सकते हैं । हालांकि follwing वाले नहीं करते हैं।

var a=String() // Create a new Non Object string. returns a typeof==='string' 
var a=Number() // Create a new Non Object Number. returns a typeof==='number'
var a=Boolean() //Create a new Non Object Boolean. returns a typeof==='boolean'

उपयोगकर्ता परिभाषित कार्य विशेष मामले हैं।

var a=UserDefinedFunction() //may or may not create an object of type UserDefinedFunction() based on how it is defined.

चूंकि फंक्शन टाइप ऑब्जेक्ट्स नई ऑब्जेक्ट्स बना सकते हैं जिन्हें वे कन्स्ट्रक्टर्स भी कहते हैं ।

हर कंस्ट्रक्टर / फ़ंक्शन (चाहे वह उपयोगकर्ता द्वारा निर्मित या परिभाषित किया गया हो) में स्वचालित रूप से "प्रोटोटाइप" नामक एक संपत्ति होती है जिसका डिफ़ॉल्ट रूप से मूल्य एक ऑब्जेक्ट के रूप में सेट किया जाता है। इस ऑब्जेक्ट में स्वयं "कंस्ट्रक्टर" नामक एक संपत्ति है जो डिफ़ॉल्ट रूप से कंस्ट्रक्टर / फ़ंक्शन को वापस करता है ।

उदाहरण के लिए जब हम किसी फ़ंक्शन को परिभाषित करते हैं

function UserDefinedFunction()
{
}

स्वचालित रूप से होता है

UserDefinedFunction.prototype={constructor:UserDefinedFunction}

यह "प्रोटोटाइप" संपत्ति केवल फ़ंक्शन प्रकार ऑब्जेक्ट्स में मौजूद है (और गैर फ़ंक्शन प्रकार ऑब्जेक्ट्स में कभी नहीं )।

ऐसा तब होता है क्योंकि जब एक नई वस्तु बनाई जाती है (नए ऑपरेटर का उपयोग करके) यह कंस्ट्रक्टर फ़ंक्शन के वर्तमान प्रोटोटाइप ऑब्जेक्ट से सभी गुणों और विधियों को इनहेरिट करता है, जो कि नई बनाई गई ऑब्जेक्ट में एक आंतरिक संदर्भ बनाया जाता है, जो कि कंस्ट्रक्टर फ़ंक्शन के वर्तमान प्रोटोटाइप ऑब्जेक्ट द्वारा संदर्भित ऑब्जेक्ट को संदर्भित करता है।

विरासत में मिली संपत्तियों को संदर्भित करने के लिए बनाई गई इस "आंतरिक संदर्भ" को ऑब्जेक्ट के प्रोटोटाइप के रूप में जाना जाता है (जो कि कंस्ट्रक्टर की "प्रोटोटाइप" संपत्ति द्वारा संदर्भित ऑब्जेक्ट को संदर्भित करता है लेकिन इससे अलग है)। किसी भी ऑब्जेक्ट (फ़ंक्शन या गैर फ़ंक्शन) के लिए, Object.getPrototypeOf () विधि का उपयोग करके इसे पुनर्प्राप्त किया जा सकता है । इस विधि का उपयोग करके किसी वस्तु की प्रोटोटाइप श्रृंखला का पता लगाया जा सकता है।

साथ ही, बनाई गई प्रत्येक वस्तु ( फंक्शन टाइप या नॉन फंक्शन टाइप ) में एक "कंस्ट्रक्टर" संपत्ति होती है, जो कंस्ट्रक्टर फ़ंक्शन के प्रोटोटाइप प्रॉपर्टी द्वारा संदर्भित ऑब्जेक्ट से विरासत में मिली है। डिफ़ॉल्ट रूप से यह "कंस्ट्रक्टर" गुण कंस्ट्रक्टर फ़ंक्शन का संदर्भ देता है जिसने इसे बनाया है (यदि कंस्ट्रक्टर फ़ंक्शन का डिफ़ॉल्ट "प्रोटोटाइप" नहीं बदला गया है)।

सभी फ़ंक्शन प्रकार ऑब्जेक्ट्स के लिए कंस्ट्रक्टर फ़ंक्शन हमेशा फ़ंक्शन होता है () {}

के लिए गैर समारोह प्रकार की वस्तुओं (जैसे जावास्क्रिप्ट मठ वस्तु में निर्मित) निर्माता समारोह समारोह है कि यह बनाया गया है। के लिए मठ वस्तु यह है समारोह वस्तु () {}

ऊपर बताई गई सभी अवधारणा किसी भी सहायक कोड के बिना समझने में थोड़ी मुश्किल हो सकती है। अवधारणा को समझने के लिए कृपया निम्न कोड लाइन से गुजरें। बेहतर समझ रखने के लिए इसे निष्पादित करने का प्रयास करें।

function UserDefinedFunction()
{ 

} 

/* creating the above function automatically does the following as mentioned earlier

UserDefinedFunction.prototype={constructor:UserDefinedFunction}

*/


var newObj_1=new UserDefinedFunction()

alert(Object.getPrototypeOf(newObj_1)===UserDefinedFunction.prototype)  //Displays true

alert(newObj_1.constructor) //Displays function UserDefinedFunction

//Create a new property in UserDefinedFunction.prototype object

UserDefinedFunction.prototype.TestProperty="test"

alert(newObj_1.TestProperty) //Displays "test"

alert(Object.getPrototypeOf(newObj_1).TestProperty)// Displays "test"

//Create a new Object

var objA = {
        property1 : "Property1",
        constructor:Array

}


//assign a new object to UserDefinedFunction.prototype
UserDefinedFunction.prototype=objA

alert(Object.getPrototypeOf(newObj_1)===UserDefinedFunction.prototype)  //Displays false. The object referenced by UserDefinedFunction.prototype has changed

//The internal reference does not change
alert(newObj_1.constructor) // This shall still Display function UserDefinedFunction

alert(newObj_1.TestProperty) //This shall still Display "test" 

alert(Object.getPrototypeOf(newObj_1).TestProperty) //This shall still Display "test"


//Create another object of type UserDefinedFunction
var newObj_2= new UserDefinedFunction();

alert(Object.getPrototypeOf(newObj_2)===objA) //Displays true.

alert(newObj_2.constructor) //Displays function Array()

alert(newObj_2.property1) //Displays "Property1"

alert(Object.getPrototypeOf(newObj_2).property1) //Displays "Property1"

//Create a new property in objA
objA.property2="property2"

alert(objA.property2) //Displays "Property2"

alert(UserDefinedFunction.prototype.property2) //Displays "Property2"

alert(newObj_2.property2) // Displays Property2

alert(Object.getPrototypeOf(newObj_2).property2) //Displays  "Property2"

हर वस्तु की प्रोटोटाइप श्रृंखला अंततः Object.prototype (जिसका स्वयं कोई प्रोटोटाइप ऑब्जेक्ट नहीं है) पर वापस आ जाती है। किसी वस्तु के प्रोटोटाइप चेन को ट्रेस करने के लिए निम्नलिखित कोड का उपयोग किया जा सकता है

var o=Starting object;

do {
    alert(o + "\n" + Object.getOwnPropertyNames(o))

}while(o=Object.getPrototypeOf(o))

विभिन्न वस्तुओं के लिए प्रोटोटाइप श्रृंखला निम्नानुसार काम करती है।

  • हर फंक्शन ऑब्जेक्ट (फंक्शन ऑब्जेक्ट में निर्मित) -> फंक्शन.प्रोटोटाइप -> ऑब्जेक्ट.प्रोटोटाइप -> अशक्त
  • साधारण वस्तुएं (नई वस्तु द्वारा बनाई गई) (या {} जिसमें मैथ ऑब्जेक्ट बनाया गया है) -> ऑब्जेक्ट.प्रोटोटाइप -> अशक्त
  • नई या Object.create के साथ बनाई गई वस्तु -> एक या अधिक प्रोटोटाइप चेन -> Object.prototype -> अशक्त

किसी भी प्रोटोटाइप के बिना एक वस्तु बनाने के लिए निम्नलिखित का उपयोग करें:

var o=Object.create(null)
alert(Object.getPrototypeOf(o)) //Displays null

कोई सोच सकता है कि कंस्ट्रक्टर की प्रोटोटाइप प्रॉपर्टी को अशक्त करने के लिए अशक्त प्रोटोटाइप के साथ एक ऑब्जेक्ट बनाया जाएगा। हालाँकि ऐसे मामलों में नव निर्मित वस्तु का प्रोटोटाइप Object.prototyp पर सेट होता है और इसका निर्माता ऑब्जेक्ट को कार्य करने के लिए सेट किया जाता है। यह निम्नलिखित कोड द्वारा प्रदर्शित किया जाता है

function UserDefinedFunction(){}
UserDefinedFunction.prototype=null// Can be set to any non object value (number,string,undefined etc.)

var o=new UserDefinedFunction()
alert(Object.getPrototypeOf(o)==Object.prototype)   //Displays true
alert(o.constructor)    //Displays Function Object

इस लेख के सारांश में निम्नलिखित हैं

  • फंक्शन टाइप्स और नॉन फंक्शन टाइप्स दो तरह के होते हैं
  • केवल फ़ंक्शन प्रकार ऑब्जेक्ट ऑपरेटर नया का उपयोग करके एक नई वस्तु बना सकते हैं । इस प्रकार बनाई गई वस्तुएँ नॉन फंक्शन टाइप की वस्तुएँ हैं। गैर समारोह प्रकार वस्तुओं आगे एक वस्तु का उपयोग कर नहीं बना सकते ऑपरेटर नई

  • डिफ़ॉल्ट रूप से सभी फ़ंक्शन प्रकार ऑब्जेक्ट में "प्रोटोटाइप" गुण होता है। यह "प्रोटोटाइप" संपत्ति एक ऑब्जेक्ट का संदर्भ देती है जिसमें "कंस्ट्रक्टर" गुण होता है जो डिफ़ॉल्ट रूप से फ़ंक्शन प्रकार ऑब्जेक्ट को स्वयं संदर्भित करता है।

  • सभी ऑब्जेक्ट्स ( फ़ंक्शन प्रकार और गैर फ़ंक्शन प्रकार ) में एक "कंस्ट्रक्टर" गुण होता है जो डिफ़ॉल्ट रूप से फ़ंक्शन प्रकार ऑब्जेक्ट / कंस्ट्रक्टर द्वारा बनाया जाता है।

  • प्रत्येक वस्तु जो आंतरिक रूप से निर्मित होती है वह उस निर्माता की "प्रोटोटाइप" संपत्ति द्वारा संदर्भित वस्तु को संदर्भित करती है जिसने इसे बनाया था। इस ऑब्जेक्ट को बनाए गए ऑब्जेक्ट के प्रोटोटाइप के रूप में जाना जाता है (जो फ़ंक्शन प्रकार ऑब्जेक्ट "प्रोटोटाइप" संपत्ति से भिन्न होता है जिसे यह संदर्भित करता है)। इस तरह से बनाई गई वस्तु कंस्ट्रक्टर की "प्रोटोटाइप" संपत्ति (ऑब्जेक्ट निर्माण के समय) द्वारा संदर्भित ऑब्जेक्ट में परिभाषित तरीकों और गुणों तक सीधे पहुंच सकती है।

  • एक ऑब्जेक्ट का प्रोटोटाइप (और इसलिए इसके विरासत में मिली संपत्ति के नाम) Object.getPrototypeOf () विधि का उपयोग करके पुनर्प्राप्त किया जा सकता है । वास्तव में इस पद्धति का उपयोग वस्तु की संपूर्ण प्रोटोटाइप श्रृंखला को नेविगेट करने के लिए किया जा सकता है।

  • प्रत्येक वस्तु की प्रोटोटाइप श्रृंखला अंततः Object.prototype (जब तक कि ऑब्जेक्ट Object.create (अशक्त) का उपयोग करके बनाई गई है, जिस स्थिति में ऑब्जेक्ट का कोई प्रोटोटाइप नहीं है) वापस आ जाता है।

  • टाइपोफ़ (नया ऐरे ()) === 'ऑब्जेक्ट' भाषा के डिज़ाइन से है न कि डगलस क्रॉकफोर्ड द्वारा बताई गई एक गलती से।

  • कंस्ट्रक्टर की प्रोटोटाइप संपत्ति को अशक्त (या अपरिभाषित, संख्या, सत्य, असत्य, स्ट्रिंग) के लिए सेट करने से अशक्त प्रोटोटाइप के साथ कोई वस्तु नहीं बनेगी। ऐसे मामलों में नव निर्मित वस्तु का प्रोटोटाइप Object.prototyp पर सेट होता है और इसका निर्माता ऑब्जेक्ट को कार्य करने के लिए सेट किया जाता है।

उम्मीद है की यह मदद करेगा।


24

prototypalवंशानुक्रम की अवधारणा कई डेवलपर्स के लिए सबसे जटिल है। आइए prototypal inheritanceबेहतर समझने के लिए समस्या की जड़ को समझने की कोशिश करें । चलो एक plainसमारोह के साथ शुरू करते हैं।

यहां छवि विवरण दर्ज करें

यदि हम एक newऑपरेटर का उपयोग करते हैं Tree function, तो हम इसे एक constructorफ़ंक्शन के रूप में कहते हैं ।

यहां छवि विवरण दर्ज करें

हर JavaScriptफंक्शन में ए prototype। जब आप लॉग इन करते हैं Tree.prototype, तो आप प्राप्त करते हैं ...

यहां छवि विवरण दर्ज करें

यदि आप उपर्युक्त console.log()आउटपुट को देखते हैं, तो आप एक निर्माणकर्ता संपत्ति को Tree.prototypeऔर __proto__संपत्ति को भी देख सकते हैं। यह __proto__दर्शाता है prototypeकि यह functionबंद है, और चूंकि यह अभी तक JavaScript functionबिना किसी inheritanceसेट के एक मैदान है, यह संदर्भित करता है कि Object prototypeजावास्क्रिप्ट में बनाया गया कुछ है ...

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype

यह .toString, .toValue, .hasOwnPropertyआदि जैसी चीजें हैं ...

__proto__जो लाया गया था मेरा मोज़िला पदावनत है और इसे Object.getPrototypeOfप्राप्त करने के लिए विधि द्वारा प्रतिस्थापित किया गया है object's prototype

यहां छवि विवरण दर्ज करें

Object.getPrototypeOf(Tree.prototype); // Object {} 

चलो हमारे लिए एक विधि जोड़ें Tree prototype

यहां छवि विवरण दर्ज करें

हमने इसमें संशोधन किया है Rootऔर इसमें एक functionशाखा जोड़ी है ।

यहां छवि विवरण दर्ज करें

इसका मतलब है कि जब आप एक बनाते instanceहैं Tree, तो आप इसे branchविधि कह सकते हैं ।

यहां छवि विवरण दर्ज करें

हम भी जोड़ सकते हैं primitivesया objectsहमारे लिए Prototype

यहां छवि विवरण दर्ज करें

चलो child-treeहमारे लिए एक जोड़ें Tree

यहां छवि विवरण दर्ज करें

यहां ट्री से Childइसकी विरासत मिलती है prototype, जो हम यहां कर रहे हैं वह Object.create()विधि का उपयोग करके आप जो भी पास करते हैं, उसके आधार पर एक नई वस्तु बनाते हैं Tree.prototype। इस मामले में हम जो कर रहे हैं वह बाल के प्रोटोटाइप को एक नई वस्तु के रूप में स्थापित कर रहा है जो प्रोटोटाइप के समान दिखता है Tree। अगला हम सेट कर रहे हैं Child's constructor to Child, अगर हम इसे इंगित नहीं करेंगे Tree()

यहां छवि विवरण दर्ज करें

Childअब इसके अपने हैं prototype, इसके __proto__अंक Treeऔर Tree's prototypeआधार की ओर इशारा करते हैं Object

Child  
|
 \
  \
   Tree.prototype
   - branch
   |
   |
    \
     \
      Object.prototype
      -toString
      -valueOf
      -etc., etc.

अब आप एक बनाने instanceकी Childऔर कॉल branchजो मूल रूप में उपलब्ध है Tree। हमने वास्तव में अपने branchको परिभाषित नहीं किया है Child prototype। BUT, Root prototypeजिसमें से बच्चा विरासत में मिला है।

यहां छवि विवरण दर्ज करें

जेएस में सब कुछ एक वस्तु नहीं है, सब कुछ एक वस्तु की तरह काम कर सकता है।

Javascriptstrings, number, booleans, undefined, null.उनमें आदिम हैं जैसे वे नहीं हैं object(i.e reference types), लेकिन निश्चित रूप से एक की तरह कार्य कर सकते हैं object। आइए यहां एक उदाहरण देखें।

यहां छवि विवरण दर्ज करें

इस सूची की पहली पंक्ति में, primitiveनाम के लिए एक स्ट्रिंग मान दिया गया है। दूसरी पंक्ति एक नाम की तरह व्यवहार करती है objectऔर charAt(0)डॉट नोटेशन का उपयोग करके कॉल करती है।

पर्दे के पीछे यही होता है: // JavaScriptइंजन क्या करता है

यहां छवि विवरण दर्ज करें

String objectकेवल के लिए एक बयान मौजूद है इससे पहले कि यह (नामक एक प्रक्रिया को नष्ट कर दिया है autoboxing)। चलो फिर से हमारे पास लौट आएं prototypal inheritance

  • Javascriptके delegationआधार पर वंशानुक्रम का समर्थन करता है prototypes
  • प्रत्येक के Functionपास एक prototypeसंपत्ति है, जो किसी अन्य वस्तु को संदर्भित करता है।
  • properties/functionsयदि यह मौजूद नहीं है तो objectस्वयं या prototypeश्रृंखला के माध्यम से देखा जाता है

एक prototypeजे एस में जो एक वस्तु है yieldsयदि आप किसी अन्य की मूल करने के लिए object[अर्थात .. प्रतिनिधिमंडल] का Delegation मतलब है कि यदि आप कुछ करने में असमर्थ हैं, तो आप किसी और को यह करने के लिए कहेंगे।

यहां छवि विवरण दर्ज करें

https://jsfiddle.net/say0tzpL/1/

यदि आप उपर्युक्त फिडल को देखते हैं, तो कुत्ते के पास toStringविधि तक पहुंच है , लेकिन इसमें उपलब्ध नहीं है, लेकिन प्रोटोटाइप श्रृंखला के माध्यम से उपलब्ध है:Object.prototype

यहां छवि विवरण दर्ज करें

यदि आप नीचे एक को देखते हैं, तो हम उस callविधि का उपयोग करने की कोशिश कर रहे हैं जो हर में उपलब्ध है function

यहां छवि विवरण दर्ज करें

https://jsfiddle.net/rknffckc/

यदि आप उपर्युक्त फिडल को देखते हैं, तो Profileफंक्शन की callविधि का उपयोग होता है, लेकिन इसमें उपलब्ध नहीं है, लेकिन प्रोटोटाइप श्रृंखला के माध्यम से उपलब्ध है:Function.prototype

यहां छवि विवरण दर्ज करें

नोट: prototype फ़ंक्शन कंस्ट्रक्टर __proto__की एक संपत्ति है , जबकि फ़ंक्शन कंस्ट्रक्टर से निर्मित वस्तुओं की एक संपत्ति है। प्रत्येक फ़ंक्शन एक prototypeसंपत्ति के साथ आता है जिसका मूल्य एक खाली है object। जब हम फ़ंक्शन का एक उदाहरण बनाते हैं, तो हमें एक आंतरिक संपत्ति मिलती है [[Prototype]]या __proto__जिसका संदर्भ फ़ंक्शन का प्रोटोटाइप होता है constructor

यहां छवि विवरण दर्ज करें

उपरोक्त आरेख थोड़ा जटिल लग रहा है, लेकिन पूरी तस्वीर को कैसे prototype chainingकाम करता है, इस बारे में बताता है। आइए इस पर चलें धीरे:

दो उदाहरण हैं b1और b2, जिनके निर्माता हैं Barऔर माता-पिता फू हैं और प्रोटोटाइप श्रृंखला से दो तरीके हैं identifyऔर के speakमाध्यम से BarऔरFoo

यहां छवि विवरण दर्ज करें

https://jsfiddle.net/kbp7jr7n/

यदि आप ऊपर दिए गए कोड को देखते हैं, तो हमारे पास Fooकंस्ट्रक्टर है, जिसके पास विधि है identify()और Barकंस्ट्रक्टर जिसके पास speakविधि है। हम दो Barउदाहरण बनाते हैं b1और b2जिनके मूल प्रकार हैं Foo। अब कॉलिंग speakविधि के दौरान Bar, हम यह पहचानने में सक्षम हैं कि prototypeचेन के माध्यम से कौन कॉल कर रहा है ।

यहां छवि विवरण दर्ज करें

Barअब इसके सभी तरीकों Fooको परिभाषित किया गया है prototype। आइए और यह समझने में Object.prototypeऔर खुदाई करें Function.prototypeकि वे कैसे संबंधित हैं। यदि आप के निर्माता को देखते हैं Foo, Barऔर Objectहैं Function constructor

यहां छवि विवरण दर्ज करें

prototypeकी Barहै Foo, prototypeकी Fooहै Objectऔर अगर तुम करीब से देखो prototypeकी Fooसे संबंधित है Object.prototype

यहां छवि विवरण दर्ज करें

इससे पहले कि हम इसे बंद करें, चलो ऊपर दिए गए सब कुछ को संक्षेप में बताने के लिए यहां एक छोटे से कोड के साथ लपेटें । हम instanceofयह जांचने के लिए ऑपरेटर का उपयोग कर रहे हैं कि क्या objectइसकी prototypeश्रृंखला prototypeमें कोई है constructorजो नीचे की संपत्ति पूरे बड़े आरेख को संक्षेप में प्रस्तुत करता है।

यहां छवि विवरण दर्ज करें

मुझे उम्मीद है कि इस जानकारी में कुछ जानकारी है, मुझे पता है कि यह थोड़े से समझ के लिए बड़ा हो सकता है ... सरल शब्दों में इसका सिर्फ वस्तुओं से जुड़ा हुआ है !!!!


22

इस ".प्रोटोटाइप" संपत्ति का सटीक उद्देश्य क्या है?

मानक कक्षाओं के लिए इंटरफ़ेस एक्स्टेंसिबल हो जाता है। उदाहरण के लिए, आप Arrayकक्षा का उपयोग कर रहे हैं और आपको अपनी सभी सरणी वस्तुओं के लिए एक कस्टम धारावाहिक जोड़ने की भी आवश्यकता है। क्या आप किसी उपवर्ग को कोड करने में समय व्यतीत करेंगे, या रचना का उपयोग करेंगे या ... प्रोटोटाइप गुण इसे हल करके उपयोगकर्ताओं को किसी वर्ग के लिए उपलब्ध सदस्यों / विधियों के सटीक सेट को नियंत्रित करने देता है।

एक अतिरिक्त व्यवहार्य-सूचक के रूप में प्रोटोटाइप के बारे में सोचो। जब कुछ सदस्य मूल कक्षा से गायब होते हैं, तो प्रोटोटाइप को रनटाइम पर देखा जाता है।


21

यह प्रोटोटाइप श्रृंखलाओं को दो श्रेणियों में वर्गीकृत करने में मदद कर सकता है।

कंस्ट्रक्टर पर विचार करें:

 function Person() {}

का मान Object.getPrototypeOf(Person)एक कार्य है। वास्तव में, यह है Function.prototype। चूंकि Personएक फ़ंक्शन के रूप में बनाया गया था, इसलिए यह उसी प्रोटोटाइप फ़ंक्शन ऑब्जेक्ट को साझा करता है जो सभी फ़ंक्शन हैं। यह वैसा ही है Person.__proto__, लेकिन उस संपत्ति का उपयोग नहीं किया जाना चाहिए। वैसे भी, Object.getPrototypeOf(Person)आप के साथ प्रभावी रूप से सीढ़ी को चलना है जिसे प्रोटोटाइप श्रृंखला कहा जाता है।

ऊपर की दिशा में श्रृंखला इस तरह दिखती है:

    PersonFunction.prototypeObject.prototype(अंतिम बिंदु)

महत्वपूर्ण यह है कि इस प्रोटोटाइप श्रृंखला का उन वस्तुओं के साथ बहुत कम संबंध है जो निर्माणPerson कर सकते हैं । उन निर्मित वस्तुओं की अपनी स्वयं की प्रोटोटाइप श्रृंखला होती है, और इस श्रृंखला में संभवतः ऊपर उल्लेखित के साथ कोई निकट पूर्वज नहीं हो सकता है।

उदाहरण के लिए इस वस्तु को लें:

var p = new Person();

p का व्यक्ति के साथ कोई प्रत्यक्ष प्रोटोटाइप-चेन संबंध नहीं है । उनका रिश्ता एक अलग है। ऑब्जेक्ट पी की अपनी प्रोटोटाइप श्रृंखला है। का उपयोग कर Object.getPrototypeOf, आप पाएंगे श्रृंखला इस प्रकार है:

    pPerson.prototypeObject.prototype(अंतिम बिंदु)

इस श्रृंखला में कोई फ़ंक्शन ऑब्जेक्ट नहीं है (हालांकि ऐसा हो सकता है)।

तो Personदो प्रकार की जंजीरों से संबंधित लगता है, जो अपना जीवन जीते हैं। एक श्रृंखला से दूसरी में "कूद" करने के लिए, आप उपयोग करते हैं:

  1. .prototype: कंस्ट्रक्टर की चेन से बनाई गई ऑब्जेक्ट की चेन तक जंप करें। यह संपत्ति इस प्रकार केवल फ़ंक्शन ऑब्जेक्ट्स के लिए परिभाषित होती है (जैसा कि newकेवल फ़ंक्शन पर उपयोग किया जा सकता है)।

  2. .constructor: बनाई गई ऑब्जेक्ट की चेन से कंस्ट्रक्टर की चेन तक जंप करें।

इसमें शामिल दो प्रोटोटाइप श्रृंखलाओं की एक दृश्य प्रस्तुति है, जिन्हें कॉलम के रूप में दर्शाया गया है:

यहां छवि विवरण दर्ज करें

संक्षेपित करते हुए:

prototypeसंपत्ति का कोई जानकारी देता है विषय के प्रोटोटाइप श्रृंखला है, लेकिन वस्तुओं के द्वारा बनाई गई विषय।

यह कोई आश्चर्य की बात नहीं है कि संपत्ति के नाम prototypeपर भ्रम पैदा हो सकता है। यह स्पष्ट हो सकता है कि अगर इस संपत्ति का नाम prototypeOfConstructedInstancesया उस रेखा के साथ कुछ था।

आप दो प्रोटोटाइप श्रृंखलाओं के बीच आगे-पीछे कूद सकते हैं:

Person.prototype.constructor === Person

prototypeसंपत्ति के लिए एक अलग वस्तु को स्पष्ट रूप से निर्दिष्ट करके इस समरूपता को तोड़ा जा सकता है (इसके बारे में बाद में)।

एक फ़ंक्शन बनाएं, दो ऑब्जेक्ट प्राप्त करें

Person.prototypeएक वस्तु है जिसे उसी समय Personबनाया गया था जब फ़ंक्शन बनाया गया था। यह Personकंस्ट्रक्टर के रूप में है, भले ही वह कंस्ट्रक्टर वास्तव में अभी तक निष्पादित नहीं हुआ है। तो एक ही समय में दो ऑब्जेक्ट बनाए जाते हैं:

  1. कार्य Personही
  2. फ़ंक्शन के निर्माण के रूप में कहा जाता है जब ऑब्जेक्ट प्रोटोटाइप के रूप में कार्य करेगा

दोनों ऑब्जेक्ट हैं, लेकिन उनकी अलग-अलग भूमिकाएँ हैं: फ़ंक्शन ऑब्जेक्ट का निर्माण होता है , जबकि दूसरी ऑब्जेक्ट किसी भी ऑब्जेक्ट के प्रोटोटाइप का प्रतिनिधित्व करती है जो फ़ंक्शन का निर्माण करेगा। प्रोटोटाइप ऑब्जेक्ट अपनी प्रोटोटाइप श्रृंखला में निर्मित वस्तु का जनक बन जाएगा।

चूंकि एक फ़ंक्शन भी एक वस्तु है, इसकी स्वयं की प्रोटोटाइप श्रृंखला में इसका अपना माता-पिता भी है, लेकिन याद रखें कि ये दो श्रृंखलाएं अलग-अलग चीजों के बारे में हैं।

यहाँ कुछ समानताएँ हैं जो समस्या को समझने में मदद कर सकती हैं - ये सभी प्रिंट true:

function Person() {};

// This is prototype chain info for the constructor (the function object):
console.log(Object.getPrototypeOf(Person) === Function.prototype);
// Step further up in the same hierarchy:
console.log(Object.getPrototypeOf(Function.prototype) === Object.prototype);
console.log(Object.getPrototypeOf(Object.prototype) === null);
console.log(Person.__proto__ === Function.prototype);
// Here we swap lanes, and look at the constructor of the constructor
console.log(Person.constructor === Function);
console.log(Person instanceof Function);

// Person.prototype was created by Person (at the time of its creation)
// Here we swap lanes back and forth:
console.log(Person.prototype.constructor === Person);
// Although it is not an instance of it:
console.log(!(Person.prototype instanceof Person));
// Instances are objects created by the constructor:
var p = new Person();
// Similarly to what was shown for the constructor, here we have
// the same for the object created by the constructor:
console.log(Object.getPrototypeOf(p) === Person.prototype);
console.log(p.__proto__ === Person.prototype);
// Here we swap lanes, and look at the constructor
console.log(p.constructor === Person);
console.log(p instanceof Person);

प्रोटोटाइप श्रृंखला में स्तर जोड़ना

हालाँकि एक प्रोटोटाइप ऑब्जेक्ट तब बनता है जब आप एक कंस्ट्रक्टर फ़ंक्शन बनाते हैं, तो आप उस ऑब्जेक्ट को अनदेखा कर सकते हैं, और किसी अन्य ऑब्जेक्ट को असाइन कर सकते हैं जिसे उस निर्माता द्वारा बनाए गए किसी भी बाद के इंस्टेंस के लिए प्रोटोटाइप के रूप में उपयोग किया जाना चाहिए।

उदाहरण के लिए:

function Thief() { }
var p = new Person();
Thief.prototype = p; // this determines the prototype for any new Thief objects:
var t = new Thief();

अब t की प्रोटोटाइप श्रृंखला p की तुलना में एक कदम लंबी है :

    tpPerson.prototypeObject.prototype(अंतिम बिंदु)

अन्य प्रोटोटाइप श्रृंखला अब नहीं है: Thiefऔर Personभाई-बहन एक ही माता-पिता को अपनी प्रोटोटाइप श्रृंखला में साझा कर रहे हैं:

    Person}
    Thief  } → Function.prototypeObject.prototype(अंतिम बिंदु)

पहले प्रस्तुत ग्राफिक को फिर इस तक बढ़ाया जा सकता है (मूल Thief.prototypeको छोड़ दिया गया है):

यहां छवि विवरण दर्ज करें

नीली रेखाएं प्रोटोटाइप श्रृंखलाओं का प्रतिनिधित्व करती हैं, अन्य रंगीन रेखाएं अन्य संबंधों का प्रतिनिधित्व करती हैं:

  • एक वस्तु और उसके निर्माता के बीच
  • एक कंस्ट्रक्टर और प्रोटोटाइप ऑब्जेक्ट के बीच जिसका उपयोग वस्तुओं के निर्माण के लिए किया जाएगा

18

ऑब्जेक्ट-ओरिएंटेड जावास्क्रिप्ट के लिए निश्चित गाइड - एक बहुत ही संक्षिप्त और स्पष्ट ~ 30 मिनट का वीडियो स्पष्टीकरण (प्रोटोटाइपल इनहेरिटेंस विषय 5:45 से शुरू होता है , हालांकि मैं पूरे वीडियो को सुनना चाहता हूं)। इस वीडियो के लेखक ने जावास्क्रिप्ट ऑब्जेक्ट विज़ुअलाइज़र वेबसाइट http://www.objectplayground.com/ भी बनाया ।यहां छवि विवरण दर्ज करें यहां छवि विवरण दर्ज करें


1
महान वीडियो संदर्भ
lukeaus

16

जब obj_n.prop_Xइसे संदर्भित किया जा रहा था, तो मैंने "प्रोटोटाइप चेन" को पुनरावर्ती सम्मेलन के रूप में समझाने में मददगार पाया :

यदि obj_n.prop_Xमौजूद नहीं है, तो जाँच करें obj_n+1.prop_Xकि कहाँ हैobj_n+1 = obj_n.[[prototype]]

यदि prop_Xअंत में k- वें प्रोटोटाइप ऑब्जेक्ट में पाया जाता है

obj_1.prop_X = obj_1.[[prototype]].[[prototype]]..(k-times)..[[prototype]].prop_X

आप यहाँ उनके गुणों द्वारा जावास्क्रिप्ट वस्तुओं के संबंध का एक ग्राफ पा सकते हैं:

जे एस वस्तुओं ग्राफ

http://jsobjects.org


14

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


11

यहां दो अलग-अलग लेकिन संबंधित संस्थाएं हैं जिन्हें समझाने की आवश्यकता है:

  • .prototypeकार्यों की संपत्ति।
  • सभी वस्तुओं की [[Prototype]][1] संपत्ति [२]

ये दो अलग-अलग चीजें हैं।

[[Prototype]]संपत्ति:

यह एक संपत्ति है जो सभी [2] वस्तुओं पर मौजूद है ।

यहां जो कुछ संग्रहीत किया गया है, वह एक अन्य वस्तु है, जो कि एक वस्तु के रूप में स्वयं की है, [[Prototype]]जो किसी अन्य वस्तु की ओर इशारा करती है। उस अन्य वस्तु का [[Prototype]]अपना है। यह कहानी तब तक जारी रहती है जब तक कि आप सभी प्रकार की वस्तुओं (जैसे .toString) पर पहुँच योग्य तरीकों को प्रदान करने वाली प्रोटोटाइपिक वस्तु तक नहीं पहुँच जाते ।

[[Prototype]]संपत्ति क्या रूपों का हिस्सा है [[Prototype]]श्रृंखला। [[Prototype]]वस्तुओं की यह श्रृंखला है , जब जांच की जाती है, उदाहरण के लिए, [[Get]]या [[Set]]किसी ऑब्जेक्ट पर कार्रवाई की जाती है:

var obj = {}
obj.a         // [[Get]] consults prototype chain
obj.b = 20    // [[Set]] consults prototype chain

.prototypeसंपत्ति:

यह एक संपत्ति है जो केवल कार्यों पर पाई जाती है। एक बहुत ही सरल कार्य का उपयोग करना:

function Bar(){};

.prototypeसंपत्ति एक वस्तु धारण कि को सौंपा जाएगा b.[[Prototype]]जब आप ऐसा करेंगे var b = new Bar। आप आसानी से इसकी जांच कर सकते हैं:

// Both assign Bar.prototype to b1/b2[[Prototype]]
var b = new Bar;
// Object.getPrototypeOf grabs the objects [[Prototype]]
console.log(Object.getPrototypeOf(b) === Bar.prototype) // true

सबसे महत्वपूर्ण में से एक .prototypeरों कि है की Objectसमारोह । यह प्रोटोटाइप प्रोटोटाइप ऑब्जेक्ट रखता है जिसमें सभी [[Prototype]]चेन होते हैं। इस पर, नई वस्तुओं के लिए सभी उपलब्ध तरीके परिभाषित हैं:

// Get properties that are defined on this object
console.log(Object.getOwnPropertyDescriptors(Object.prototype))

अब, चूंकि .prototypeएक वस्तु है, इसके पास एक [[Prototype]]संपत्ति है। आप के लिए किसी भी कार्य नहीं करते हैं जब Function.prototype, .prototypeके [[Prototype]]प्रोटोटाइप वस्तु को अंक ( Object.prototype)। जब भी आप एक नया फ़ंक्शन बनाते हैं तो यह स्वचालित रूप से किया जाता है।

इस तरह, किसी भी समय आप new Bar;प्रोटोटाइप चेन को आपके लिए सेट कर देते हैं, आपको सब कुछ परिभाषित हो जाता है Bar.prototypeऔर सब कुछ परिभाषित हो जाता है Object.prototype:

var b = new Bar;
// Get all Bar.prototype properties
console.log(b.__proto__ === Bar.prototype)
// Get all Object.prototype properties
console.log(b.__proto__.__proto__ === Object.prototype)

जब आप ऐसा करने के लिए कर कार्य Function.prototypeसब आप कर रहे हैं प्रोटोटाइप श्रृंखला का विस्तार किसी अन्य वस्तु शामिल करने के लिए है। यह एक एकल लिंक की गई सूची में एक प्रविष्टि की तरह है।

यह मूल रूप से [[Prototype]]श्रृंखला को बदलने की अनुमति देता है जो गुणों को उस Function.prototypeफ़ंक्शन पर परिभाषित किया जाता है जिसे फ़ंक्शन द्वारा बनाई गई किसी भी ऑब्जेक्ट द्वारा देखा जाना चाहिए।


[१: जो किसी को भ्रमित नहीं करेगा; कई कार्यान्वयन में संपत्ति के माध्यम से उपलब्ध कराया गया__proto__
[२]: सिवाय सभी के null


10

मैं आपको प्रोटोटाइप के बारे में मेरी समझ बताता हूं। मैं यहाँ अन्य भाषाओं के साथ विरासत की तुलना नहीं करने जा रहा हूँ। काश लोग भाषा की तुलना करना बंद कर देते, और भाषा को ही समझ लेते। प्रोटोटाइप और प्रोटोटाइप की विरासत को समझना इतना सरल है, जैसा कि मैं आपको नीचे दिखाऊंगा।

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

var model = {x:2};
var product = Object.create(model);
model.y = 5;
product.y
=>5

प्रत्येक वस्तु में [[प्रोटोटाइप]] नामक एक आंतरिक गुण होता है, जिसे Object.getPrototypeOf()फ़ंक्शन द्वारा एक्सेस किया जा सकता है । Object.create(model)एक नया ऑब्जेक्ट बनाता है और इसे सेट करता है [[प्रोटोटाइप]] ऑब्जेक्ट मॉडल के लिए संपत्ति । इसलिए जब आप करते हैं Object.getPrototypeOf(product), तो आपको ऑब्जेक्ट मॉडल मिलेगा ।

उत्पाद में गुण निम्नलिखित तरीके से संभाले जाते हैं:

  • जब किसी प्रॉपर्टी को सिर्फ पढ़ने के लिए एक्सेस किया जाता है तो उसकी वैल्यू, स्कोप चेन में देखी जाती है। वेरिएबल की खोज प्रॉडक्ट के ऊपर से शुरू होकर इसके प्रोटोटाइप तक होती है। यदि खोज में ऐसा कोई चर पाया जाता है, तो खोज को वहीं रोक दिया जाता है, और मान लौटा दिया जाता है। यदि इस तरह के चर को गुंजाइश श्रृंखला में नहीं पाया जा सकता है, तो अपरिभाषित लौटा दिया जाता है।
  • जब कोई संपत्ति लिखी जाती है (परिवर्तित), तब गुण हमेशा उत्पाद वस्तु पर लिखा जाता है । यदि उत्पाद में पहले से ऐसी संपत्ति नहीं है, तो यह अंतर्निहित रूप से निर्मित और लिखित है।

प्रोटोटाइप प्रॉपर्टी का उपयोग करने वाली वस्तुओं के इस तरह के लिंकिंग को प्रोटोटाइप इनहेरिटेंस कहा जाता है। वहाँ, यह बहुत आसान है, सहमत हैं?


हमेशा असाइनमेंट पर उत्पाद पर नहीं लिखा जाता है। आप यह बहुत स्पष्ट नहीं कर रहे हैं कि उदाहरण के लिए विशिष्ट सदस्यों को आरंभीकृत किया जाना है और साझा सदस्य प्रोटोटाइप पर जा सकते हैं। विशेष रूप से जब आपके पास विशिष्ट उत्परिवर्ती सदस्य हैं: stackoverflow.com/questions/16063394/…
HMR

HMR: आपके जवाब में आपके उदाहरण में, ben.food.push ("हैमबर्गर"); लाइन प्रोटोटाइप ऑब्जेक्ट की संपत्ति को निम्न के कारण बदल देती है: 1.) पहले बेन.फूड को देखा जाता है, और किसी भी लुकअप क्रिया को बस स्कोप चेन को देखना होगा। 2.) उस बेन.फूड ऑब्जेक्ट का पुश कार्य निष्पादित किया जाता है। मेरे उत्तर में मोड लिखने से मेरा मतलब है कि जब आप स्पष्ट रूप से इसके लिए एक मूल्य निर्धारित करते हैं, जैसे: ben.food = ['Idly']; यह हमेशा उत्पाद ऑब्जेक्ट पर एक नई प्रॉपर्टी (यदि पहले से नहीं है) बनाएगा, और फिर इसके लिए मान असाइन करेगा।
अरविंद

HMR: आपकी टिप्पणी के लिए धन्यवाद, इसने मुझे अपनी समझ और मेरी समझ का परीक्षण किया।
अरविंद

जब ben.food को पुनः असाइन किया जाता है तो यह खाद्य सदस्य को तब तक छाया देगा जब तक कि ऑब्जेक्ट Object.defineProperty, Object.defineProperties या Object.create का उपयोग करके दूसरा तर्क नहीं दिया जाता (इसलिए हमेशा नहीं)। जब आप एक गटर सेटर बनाते हैं, तो आप एक पुन: असाइनमेंट के साथ प्रोटोटाइप को भी बदल सकते हैं (जैसा दिखता है)। जब यह विरासत के पैटर्न की बात आती है तो मुझे लगता है कि कंस्ट्रक्टर फ़ंक्शन को समझना मुश्किल है और कुछ प्रमुख समस्याएं हैं लेकिन अगर आप इसे समझते हैं तो यह अच्छा है। जावास्क्रिप्ट में वंशानुक्रम एक प्रोटोटाइप स्थापित करने के साथ शुरू और समाप्त नहीं होता है, इनिशियलाइज़ (निर्माणकर्ता) के रूप में अच्छी तरह से उपयोग किया जाता है।
HMR

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


10

निम्नलिखित keyValueStoreवस्तु पर विचार करें :

var keyValueStore = (function() {
    var count = 0;
    var kvs = function() {
        count++;
        this.data = {};
        this.get = function(key) { return this.data[key]; };
        this.set = function(key, value) { this.data[key] = value; };
        this.delete = function(key) { delete this.data[key]; };
        this.getLength = function() {
            var l = 0;
            for (p in this.data) l++;
            return l;
        }
    };

    return  { // Singleton public properties
        'create' : function() { return new kvs(); },
        'count' : function() { return count; }
    };
})();

मैं ऐसा करके इस वस्तु का एक नया उदाहरण बना सकता हूं:

kvs = keyValueStore.create();

इस वस्तु के प्रत्येक उदाहरण में निम्नलिखित सार्वजनिक गुण होंगे:

  • data
  • get
  • set
  • delete
  • getLength

अब, मान लीजिए कि हम इस keyValueStoreवस्तु के 100 उदाहरण बनाते हैं । हालांकि यहां तक कि get, set, delete, getLengthइन 100 उदाहरणों से प्रत्येक के लिए ठीक उसी काम करेंगे, हर मामले में इस समारोह की अपनी एक प्रतिलिपि है।

अब, कल्पना अगर आप बस एक ही हो सकता था get, set, deleteऔर getLengthप्रतिलिपि, और प्रत्येक उदाहरण है कि एक ही समारोह का संदर्भ होगा। यह प्रदर्शन के लिए बेहतर होगा और कम मेमोरी की आवश्यकता होगी।

जहाँ प्रोटोटाइप आते हैं। एक प्रोटोटाइप गुणों का एक "खाका" है जो विरासत में मिला है लेकिन उदाहरणों द्वारा कॉपी नहीं किया गया है। तो इसका मतलब है कि यह किसी वस्तु के सभी उदाहरणों के लिए केवल एक बार मेमोरी में मौजूद है और उन सभी उदाहरणों द्वारा साझा किया जाता है।

अब, keyValueStoreवस्तु पर फिर से विचार करें। मैं इसे इस तरह से फिर से लिख सकता हूं:

var keyValueStore = (function() {
    var count = 0;
    var kvs = function() {
        count++;
        this.data = {};
    };

    kvs.prototype = {
        'get' : function(key) { return this.data[key]; },
        'set' : function(key, value) { this.data[key] = value; },
        'delete' : function(key) { delete this.data[key]; },
        'getLength' : function() {
            var l = 0;
            for (p in this.data) l++;
            return l;
        }
    };

    return  {
        'create' : function() { return new kvs(); },
        'count' : function() { return count; }
    };
})();

यह keyValueStoreऑब्जेक्ट के पिछले संस्करण के समान ही है , सिवाय इसके कि इसके सभी तरीके अब एक प्रोटोटाइप में रखे गए हैं। इसका मतलब यह है, यह है कि सभी 100 उदाहरण अब इन चार तरीकों को साझा करते हैं, प्रत्येक की अपनी प्रति होने के बजाय।


9

सारांश:

  • कार्य जावास्क्रिप्ट में ऑब्जेक्ट हैं और इस प्रकार गुण हो सकते हैं
  • (कंस्ट्रक्टर) फ़ंक्शन में हमेशा एक प्रोटोटाइप संपत्ति होती है
  • जब फंक्शन को कंस्ट्रक्टर के रूप में उपयोग किया जाता है, तो newकीवर्ड को ऑब्जेक्ट प्रोटोटाइप हो जाता है। इस प्रोटोटाइप का एक संदर्भ __proto__नव निर्मित वस्तु की संपत्ति पर पाया जा सकता है ।
  • यह __proto__संपत्ति prototypeकंस्ट्रक्टर फ़ंक्शन की संपत्ति को संदर्भित करती है ।

उदाहरण:

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

let me = new Person('willem');

console.log(Person.prototype) // Person has a prototype property

console.log(Person.prototype === me.__proto__) // the __proto__ property of the instance refers to prototype property of the function.

यह क्यों उपयोगी है:

जावास्क्रिप्ट का एक तंत्र है जब वस्तुओं पर गुणों की तलाश की जाती है जिसे 'प्रोटोटाइप विरासत' कहा जाता है , यहां मूल रूप से ऐसा होता है:

  • पहले जाँच की जाती है कि क्या संपत्ति ऑब्जेक्ट पर ही स्थित है। यदि ऐसा है तो यह संपत्ति वापस कर दी जाती है।
  • यदि संपत्ति वस्तु पर स्थित नहीं है, तो यह 'प्रोटोकैन पर चढ़ जाएगा'। यह मूल रूप से प्रोटो प्रॉपर्टी द्वारा संदर्भित ऑब्जेक्ट को देखता है । वहां यह जांचता है कि प्रोटो द्वारा संदर्भित ऑब्जेक्ट पर संपत्ति उपलब्ध है या नहीं
  • यदि संपत्ति प्रोटो ऑब्जेक्ट पर स्थित नहीं है, तो यह ऑब्जेक्ट ऑब्जेक्ट तक सभी तरह से प्रोटो चेन पर चढ़ जाएगा ।
  • यदि यह वस्तु और इसके प्रोटोटाइप श्रृंखला पर कहीं भी संपत्ति नहीं पा सकता है तो यह अपरिभाषित वापस आ जाएगा।

उदाहरण के लिए:

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

let mySelf = new Person('Willem');

console.log(mySelf.__proto__ === Person.prototype);

console.log(mySelf.__proto__.__proto__ === Object.prototype);

अपडेट करें:

__proto__संपत्ति, पदावनत किया गया है, हालांकि यह अधिकांश आधुनिक ब्राउज़र में प्रोटोटाइप वस्तु संदर्भ प्राप्त करने के लिए किया जाएगा एक बेहतर तरीका लागू किया गया है:

Object.getPrototypeOf()


7

जब मैं इस प्रकार के सामान को समझने की बात करता हूं तो मैं हमेशा उपमाओं को पसंद करता हूं। मेरी राय में वर्ग बास विरासत की तुलना में 'प्रोटोटाइप विरासत' बहुत भ्रामक है, हालांकि प्रोटोटाइप बहुत सरल प्रतिमान हैं। वास्तव में प्रोटोटाइप के साथ, वास्तव में कोई विरासत नहीं है, इसलिए नाम और खुद को गुमराह करना, यह अधिक प्रकार का 'प्रतिनिधिमंडल' है।

इसकी कल्पना करें ....

आप हाई-स्कूल में हैं, और आप कक्षा में हैं और आज होने वाली एक प्रश्नोत्तरी है, लेकिन आपके पास अपने उत्तरों को भरने के लिए कलम नहीं है। रवींद्र!

आप अपने दोस्त फिनियस के पास बैठे हैं, जिसके पास एक पेन हो सकता है। आप पूछते हैं, और वह अपनी मेज के चारों ओर असफलता से देखता है, लेकिन "मेरे पास एक कलम नहीं है" कहने के बजाय, वह एक अच्छा दोस्त है जो वह अपने दूसरे दोस्त डेर के साथ जांच करता है अगर उसके पास एक कलम है। डेरप के पास वास्तव में एक अतिरिक्त पेन है और इसे फिनियस में वापस भेज दिया जाता है, जो आपके क्विज़ को पूरा करने के लिए इसे आपके पास भेजता है। डेरप ने पेन को फिनियस को सौंप दिया है, जिसने आपको उपयोग के लिए पेन सौंप दिया है।

यहां जो महत्वपूर्ण है वह यह है कि डेरेप आपको कलम नहीं देता है, क्योंकि आपका उससे सीधा संबंध नहीं है ।

यह एक सरल उदाहरण है कि प्रोटोटाइप कैसे काम करता है, जहां डेटा का एक पेड़ उस चीज़ के लिए खोजा जाता है जिसे आप खोज रहे हैं।


3

__proto__ , प्रोटोटाइप और निर्माता संबंधों को दर्शाने वाली एक और योजना : यहां छवि विवरण दर्ज करें


1

यह सिर्फ इतना है कि आपके पास पहले से ही एक वस्तु है, Object.newलेकिन कंस्ट्रक्टर सिंटैक्स का उपयोग करते समय आपके पास अभी भी कोई वस्तु नहीं है।


1

यह समझना महत्वपूर्ण है कि किसी वस्तु के प्रोटोटाइप के बीच एक अंतर है (जो कि उपलब्ध संपत्ति के Object.getPrototypeOf(obj)माध्यम से , या वंचित __proto__संपत्ति के माध्यम से उपलब्ध है) और prototypeनिर्माण कार्यों पर संपत्ति। पूर्व प्रत्येक उदाहरण पर संपत्ति है, और उत्तरार्द्ध निर्माता पर संपत्ति है। यही है, के Object.getPrototypeOf(new Foobar())रूप में एक ही वस्तु को संदर्भित करता हैFoobar.prototype

संदर्भ: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes


0

प्रोटोटाइप बनाता है नई वस्तु मौजूदा क्लोनिंग द्वारा वस्तु । इसलिए वास्तव में जब हम प्रोटोटाइप के बारे में सोचते हैं तो हम वास्तव में क्लोनिंग या इसे बनाने के बजाय किसी चीज़ की प्रतिलिपि बनाने के बारे में सोच सकते हैं ।

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