जावास्क्रिप्ट में 'प्रोटोटाइप' बनाम 'यह' का उपयोग?


776

के बीच क्या अंतर है

var A = function () {
    this.x = function () {
        //do something
    };
};

तथा

var A = function () { };
A.prototype.x = function () {
    //do something
};


THIS कीवर्ड की अवधारणा को यहाँ स्पष्ट रूप से समझाया गया है। scotch.io/@alZami/understanding-this-in-javascript
AL-zami

1
पढ़ना "यह" धागा दिखाता है कि जेएस कितना भयानक है और इसके सिद्धांत कितने डेवलपर्स के लिए अस्पष्ट हैं। भाषाओं को समझना आसान होने में क्या गलत है? मुझे लगता है कि यह समय डेवलपर्स ने भ्रमित करने वाली प्रौद्योगिकियों को अस्वीकार करने के लिए अपनी आवाज उठाई है जो व्यवसाय या विकास कार्य के लिए कोई मूल्य नहीं है।
NoChance

वस्तु पर a1.x !== a2.x:; प्रोटोटाइप पर:a1.x === a2.x
जुआन मेंडेस

जवाबों:


467

उदाहरणों के बहुत अलग परिणाम हैं।

मतभेदों को देखने से पहले, निम्नलिखित पर ध्यान दिया जाना चाहिए:

  • एक निर्माता का प्रोटोटाइप इंस्टेंस की निजी [[Prototype]]संपत्ति के माध्यम से उदाहरणों के बीच तरीकों और मूल्यों को साझा करने का एक तरीका प्रदान करता है ।
  • एक फ़ंक्शन का यह निर्धारित किया जाता है कि फ़ंक्शन कैसे कहा जाता है या बाइंड के उपयोग से (यहां चर्चा नहीं की गई है)। जहाँ किसी फ़ंक्शन को ऑब्जेक्ट पर (उदाहरण के लिए myObj.method()) कहा जाता है, तो यह विधि के भीतर ऑब्जेक्ट को संदर्भित करता है। जहां यह कॉल द्वारा या बाइंड के उपयोग से सेट नहीं किया जाता है , यह वैश्विक ऑब्जेक्ट (किसी ब्राउज़र में विंडो) या सख्त मोड में चूक करता है, अपरिभाषित रहता है।
  • जावास्क्रिप्ट एक ऑब्जेक्ट-ओरिएंटेड भाषा है, अर्थात अधिकांश मूल्य कार्य सहित ऑब्जेक्ट हैं। (स्ट्रिंग्स, नंबर और बूलियन ऑब्जेक्ट नहीं हैं।)

तो यहाँ सवाल में स्निपेट हैं:

var A = function () {
    this.x = function () {
        //do something
    };
};

इस स्थिति में, चर Aको एक मान दिया जाता है जो किसी फ़ंक्शन का संदर्भ होता है। कि समारोह का उपयोग कर कहा जाता है जब A(), समारोह है इस कॉल से सेट नहीं है तो यह वैश्विक वस्तु को चूक और अभिव्यक्ति this.xप्रभावी है window.x। इसका परिणाम यह होता है कि दाएं हाथ की तरफ फ़ंक्शन एक्सप्रेशन का एक संदर्भ दिया जाता है window.x

के मामले में:

var A = function () { };
A.prototype.x = function () {
    //do something
};

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

दूसरी पंक्ति में, A.prototyp.x को एक फ़ंक्शन का संदर्भ सौंपा गया है। यदि यह मौजूद नहीं है तो यह एक x गुण बना देगा , या यदि ऐसा होता है तो एक नया मान प्रदान करेगा। तो पहले उदाहरण के साथ अंतर जिसमें ऑब्जेक्ट की एक्स संपत्ति अभिव्यक्ति में शामिल है।

एक और उदाहरण नीचे है। यह पहले वाले के समान है (और शायद आपके कहने का मतलब क्या है):

var A = new function () {
    this.x = function () {
        //do something
    };
};

इस उदाहरण में, newऑपरेटर को फ़ंक्शन अभिव्यक्ति से पहले जोड़ा गया है ताकि फ़ंक्शन को एक निर्माता के रूप में कहा जाए। जब बुलाया जाता है new, तो फ़ंक्शन का यह एक नया ऑब्जेक्ट संदर्भित करने के लिए सेट होता है, जिसकी निजी [[Prototype]]संपत्ति निर्माता के सार्वजनिक प्रोटोटाइप को संदर्भित करने के लिए सेट होती है । इसलिए असाइनमेंट स्टेटमेंट में, xसंपत्ति इस नई ऑब्जेक्ट पर बनाई जाएगी। जब एक निर्माता के रूप में कहा जाता है, तो एक फ़ंक्शन डिफ़ॉल्ट रूप से इस ऑब्जेक्ट को वापस करता है , इसलिए एक अलग return this;बयान की आवश्यकता नहीं है ।

यह जाँचने के लिए कि A के पास x गुण है:

console.log(A.x) // function () {
                 //   //do something
                 // };

इस की एक असामान्य इस्तेमाल होता है नए निर्माता को संदर्भित करने के लिए एक ही रास्ता के बाद से होकर जाता है A.constructor । यह करना अधिक सामान्य होगा:

var A = function () {
    this.x = function () {
        //do something
    };
};
var a = new A();

एक समान परिणाम प्राप्त करने का दूसरा तरीका एक तुरंत लागू फ़ंक्शन अभिव्यक्ति का उपयोग करना है:

var A = (function () {
    this.x = function () {
        //do something
    };
}());

इस मामले में, Aदाईं ओर फ़ंक्शन को कॉल करने का रिटर्न मान असाइन किया गया है। यहां फिर से, चूंकि यह कॉल में सेट नहीं है, यह वैश्विक ऑब्जेक्ट को संदर्भित करेगा और this.xप्रभावी है window.x। चूंकि फ़ंक्शन कुछ भी वापस नहीं करता है, Aका मान होगा undefined

दो दृष्टिकोणों के बीच ये अंतर यह भी प्रकट करते हैं कि आप JSON से / से अपनी जावास्क्रिप्ट ऑब्जेक्ट्स को क्रमबद्ध और डी-सीरियल कर रहे हैं या नहीं। जब आप ऑब्जेक्ट को क्रमबद्ध करते हैं, तो किसी ऑब्जेक्ट के प्रोटोटाइप पर परिभाषित तरीकों को क्रमबद्ध नहीं किया जाता है, जो तब सुविधाजनक हो सकता है जब आप किसी ऑब्जेक्ट के डेटा भागों को क्रमबद्ध करना चाहते हैं, लेकिन यह विधि नहीं है:

var A = function () { 
    this.objectsOwnProperties = "are serialized";
};
A.prototype.prototypeProperties = "are NOT serialized";
var instance = new A();
console.log(instance.prototypeProperties); // "are NOT serialized"
console.log(JSON.stringify(instance)); 
// {"objectsOwnProperties":"are serialized"} 

संबंधित प्रश्न :

सिडेनोट: दो दृष्टिकोणों के बीच कोई महत्वपूर्ण मेमोरी सेविंग नहीं हो सकती है, हालांकि साझा करने के तरीकों और गुणों के प्रोटोटाइप का उपयोग करने से संभवतः प्रत्येक मेमोरी की तुलना में कम मेमोरी का उपयोग होगा।

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


49
@keparo: आप गलत हैं। प्रत्येक वस्तु में एक [आंतरिक] प्रोटोटाइप ऑब्जेक्ट (जो हो सकता है null) है, लेकिन यह prototypeसंपत्ति से बहुत अलग है - जो कार्यों पर है और जिस पर सभी उदाहरणों का प्रोटोटाइप सेट किया गया है जब उनके साथ निर्माण किया जाता है new। विश्वास नहीं कर सकता यह वास्तव में 87 अपवोट मिला :-(
बरगी

8
"The language is functional"क्या आप सुनिश्चित हैं कि यह क्या कार्यात्मक साधन है?
प्रेत ०

23
मैं दूसरा जो @Bergi ने प्रोटोटाइप के बारे में कहा। फ़ंक्शंस में एक प्रोटोटाइप प्रॉपर्टी होती है। फ़ंक्शंस सहित सभी ऑब्जेक्ट्स में एक और आंतरिक गुण होता है, जिसे कुछ ब्राउज़र में Object.getPrototypeOf (myObject) या myObject .__ proto__ के साथ एक्सेस किया जा सकता है। आद्य संपत्ति प्रोटोटाइप श्रृंखला में वस्तु की मूल (या वस्तु जो इस वस्तु inherits से) इंगित करता है। प्रोटोटाइप प्रॉपर्टी (जो केवल फ़ंक्शन पर है) ने उस ऑब्जेक्ट को इंगित किया जो किसी भी ऑब्जेक्ट का माता-पिता बन जाएगा जो नए कीवर्ड का उपयोग करके नई ऑब्जेक्ट बनाने के लिए फ़ंक्शन का उपयोग करते हैं।
जिम कूपर

11
यह लेख काफी भ्रामक है और भ्रमित करता है कि यह कैसे सेट किया गया है। फिर से लिखने पर काम करना।
1

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

235

जैसा कि अन्य लोगों ने कहा है कि "ए" के उपयोग से पहला संस्करण कक्षा ए के प्रत्येक उदाहरण में होता है, जिसमें फ़ंक्शन विधि "x" की अपनी स्वतंत्र प्रति होती है। जबकि "प्रोटोटाइप" का उपयोग करने का मतलब होगा कि कक्षा ए का प्रत्येक उदाहरण विधि "एक्स" की एक ही प्रति का उपयोग करेगा।

इस सूक्ष्म अंतर को दिखाने के लिए यहां कुछ कोड दिए गए हैं:

// x is a method assigned to the object using "this"
var A = function () {
    this.x = function () { alert('A'); };
};
A.prototype.updateX = function( value ) {
    this.x = function() { alert( value ); }
};

var a1 = new A();
var a2 = new A();
a1.x();  // Displays 'A'
a2.x();  // Also displays 'A'
a1.updateX('Z');
a1.x();  // Displays 'Z'
a2.x();  // Still displays 'A'

// Here x is a method assigned to the object using "prototype"
var B = function () { };
B.prototype.x = function () { alert('B'); };

B.prototype.updateX = function( value ) {
    B.prototype.x = function() { alert( value ); }
}

var b1 = new B();
var b2 = new B();
b1.x();  // Displays 'B'
b2.x();  // Also displays 'B'
b1.updateX('Y');
b1.x();  // Displays 'Y'
b2.x();  // Also displays 'Y' because by using prototype we have changed it for all instances

जैसा कि दूसरों ने उल्लेख किया है, एक विधि या दूसरे को चुनने के विभिन्न कारण हैं। मेरा नमूना सिर्फ अंतर स्पष्ट रूप से प्रदर्शित करने के लिए है।


5
यह वही होगा जो मैं होने की उम्मीद करूंगा, लेकिन जब मैंने ऊपर की तरह एक्स को बदलने के बाद एक नई वस्तु को इंस्टेंट किया, तब भी मैं 'ए' प्रदर्शित करता हूं जब तक कि मैं एक सिंगलटन की तरह ए का उपयोग नहीं करता। jsbin.com/omida4/2/edit
jellyfishtree

19
ऐसा इसलिए है क्योंकि मेरा उदाहरण गलत था। यह केवल दो साल के लिए गलत है। आह। लेकिन बिंदु अभी भी मान्य है। मैंने एक उदाहरण के साथ अद्यतन किया जो वास्तव में काम करता है। इस पर ध्यान दिलाने के लिए धन्यवाद।
बेनिरी

4
यह एक स्थिर विधि है! : D

6
हाँ ... 'प्रोटोटाइप' का अर्थ है स्थैतिक या वर्ग स्तर .. जो कि निर्मित सभी उदाहरणों द्वारा साझा किया जाएगा ... जबकि 'यह' एक उदाहरण विधि है, जिसके प्रत्येक उदाहरण की अपनी प्रति होगी
अनेर देव

7
यह स्थिर नहीं है। स्थैतिक, जैसा कि अधिकांश OO भाषाओं में उपयोग किया जाता है, का तात्पर्य है कि thisवस्तु पर कोई निर्भरता नहीं है , जो कि विधि का स्वामी है। अर्थात इस विधि का कोई ऐसा उद्देश्य नहीं है जो इसका स्वामी हो। इस मामले में एक thisऑब्जेक्ट है, जैसा कि उदाहरण में कक्षा ए में दिखाया गया है।
सीजेस्टार्ट

152

ये 2 उदाहरण लें:

var A = function() { this.hey = function() { alert('from A') } };

बनाम

var A = function() {}
A.prototype.hey = function() { alert('from prototype') };

यहां ज्यादातर लोगों (विशेष रूप से शीर्ष-रेटेड उत्तर) ने यह बताने की कोशिश की कि वे WHY की व्याख्या किए बिना कैसे अलग हैं। मुझे लगता है कि यह गलत है और यदि आप बुनियादी बातों को पहले समझ लेते हैं, तो अंतर स्पष्ट हो जाएगा। आइए पहले बुनियादी बातों को समझाने की कोशिश करें ...

क) एक फ़ंक्शन जावास्क्रिप्ट में एक वस्तु है। जावास्क्रिप्ट में हर वस्तु को एक आंतरिक संपत्ति मिलती है (मतलब, आप इसे अन्य गुणों की तरह एक्सेस नहीं कर सकते हैं, शायद क्रोम जैसे ब्राउज़रों में छोड़कर), जिसे अक्सर संदर्भित किया जाता है __proto__(आप वास्तव anyObject.__proto__में इसे देखने के लिए क्रोम में टाइप कर सकते हैं। यह सिर्फ यही है। , एक संपत्ति, और कुछ नहीं। जावास्क्रिप्ट में एक संपत्ति = एक वस्तु के अंदर एक चर, और कुछ नहीं। चर क्या करते हैं? वे चीजों को इंगित करते हैं।

तो यह __proto__संपत्ति किस ओर इशारा करती है? खैर, आमतौर पर एक और वस्तु (हम बाद में समझाएंगे)। __proto__संपत्ति के लिए जावास्क्रिप्ट को बल देने का एकमात्र तरीका किसी अन्य वस्तु को इंगित नहीं करना है var newObj = Object.create(null)। यहां तक ​​कि अगर आप ऐसा करते हैं, तो __proto__संपत्ति अभी भी ऑब्जेक्ट की संपत्ति के रूप में मौजूद है, बस यह किसी अन्य ऑब्जेक्ट को इंगित नहीं करता है, यह इंगित करता है null

यहाँ वह जगह है जहाँ ज्यादातर लोग भ्रमित होते हैं:

जब आप जावास्क्रिप्ट में एक नया फ़ंक्शन बनाते हैं (जो एक वस्तु के रूप में अच्छी तरह से याद है?), जिस क्षण इसे परिभाषित किया जाता है, जावास्क्रिप्ट स्वचालित रूप से उस फ़ंक्शन पर एक नई संपत्ति बनाता है जिसे कहा जाता है prototype। कोशिश करो:

var A = [];
A.prototype // undefined
A = function() {}
A.prototype // {} // got created when function() {} was defined

A.prototype__proto__संपत्ति से पूरी तरह अलग है । हमारे उदाहरण में, 'A' में अब 'प्रोटोटाइप' नामक TWO गुण हैं और __proto__। यह लोगों के लिए एक बड़ा भ्रम है। prototypeऔर __proto__गुण किसी भी तरह से संबंधित नहीं हैं, वे अलग-अलग चीजें हैं जो अलग-अलग मूल्यों की ओर इशारा करते हैं।

आप आश्चर्यचकित हो सकते हैं: जावास्क्रिप्ट में __proto__हर एक वस्तु पर संपत्ति क्यों बनाई गई है? खैर, एक शब्द: प्रतिनिधिमंडल । जब आप किसी ऑब्जेक्ट को किसी ऑब्जेक्ट पर कॉल करते हैं और ऑब्जेक्ट उसके पास नहीं होता है, तो जावास्क्रिप्ट ऑब्जेक्ट द्वारा संदर्भित ऑब्जेक्ट __proto__को यह देखने के लिए देखता है कि क्या यह उसके पास है। यदि यह नहीं है, तो यह उस वस्तु की __proto__संपत्ति और इसी तरह से दिखता है ... जब तक कि श्रृंखला समाप्त नहीं हो जाती। इस प्रकार नाम प्रोटोटाइप श्रृंखला । बेशक, यदि __proto__कोई वस्तु इंगित नहीं करती है और इसके बजाय null, अच्छी तरह से कठिन भाग्य को इंगित करती है , तो जावास्क्रिप्ट का एहसास होता है और आपको undefinedसंपत्ति के लिए वापस कर देगा ।

आपको यह भी आश्चर्य हो सकता है कि prototypeजब आप फ़ंक्शन को परिभाषित करते हैं , तो जावास्क्रिप्ट एक फ़ंक्शन के लिए एक संपत्ति क्यों बनाता है ? क्योंकि यह आपको बेवकूफ बनाने की कोशिश करता है, हाँ आपको बेवकूफ बनाता है कि यह वर्ग-आधारित भाषाओं की तरह काम करता है।

चलो हमारे उदाहरण के साथ चलते हैं और एक "ऑब्जेक्ट" बनाते हैं A:

var a1 = new A();

जब यह बात हुई तो पृष्ठभूमि में कुछ हो रहा है। a1एक साधारण चर है जिसे एक नई, खाली वस्तु सौंपी गई थी।

तथ्य यह है कि newएक फ़ंक्शन मंगलाचरण से पहले आपने ऑपरेटर का उपयोग किया A()था, पृष्ठभूमि में कुछ ADDITIONAL किया। newकीवर्ड एक नई वस्तु जो अब संदर्भ बनाया a1और उस वस्तु खाली है। यहाँ इसके अतिरिक्त क्या हो रहा है:

हमने कहा कि प्रत्येक फ़ंक्शन परिभाषा पर बनाई गई एक नई प्रॉपर्टी prototype(जिसे आप इसे एक्सेस कर सकते हैं, __proto__संपत्ति के विपरीत ) बनाई गई है? खैर, उस संपत्ति का इस्तेमाल अब किया जा रहा है।

तो अब हम उस बिंदु पर हैं जहाँ हमारे पास एक ताज़ा बेक्ड खाली a1वस्तु है। हमने कहा कि जावास्क्रिप्ट में सभी वस्तुओं में एक आंतरिक __proto__गुण होता है जो किसी चीज़ की ओर इशारा करता है ( a1यह भी है), चाहे वह शून्य हो या कोई अन्य वस्तु। newऑपरेटर क्या करता है यह उस __proto__संपत्ति को फ़ंक्शन की prototypeसंपत्ति को इंगित करने के लिए सेट करता है । उसे फिर से पढ़ें। यह मूल रूप से यह है:

a1.__proto__ = A.prototype;

हमने कहा कि A.prototypeएक खाली वस्तु से ज्यादा कुछ नहीं है (जब तक कि हम इसे परिभाषित करने से पहले किसी और चीज में नहीं बदलते a1)। तो अब मूल रूप a1.__proto__से उसी चीज़ की ओर A.prototypeइशारा करता है, जो कि खाली वस्तु है। वे दोनों उसी वस्तु की ओर संकेत करते हैं जो इस रेखा के बनने पर बनी थी:

A = function() {} // JS: cool. let's also create A.prototype pointing to empty {}

अब, जब var a1 = new A()वक्तव्य संसाधित होता है तो एक और बात होती है। मूल रूप A()से निष्पादित किया जाता है और यदि A कुछ इस तरह है:

var A = function() { this.hey = function() { alert('from A') } };

अंदर वह सब सामान function() { }निष्पादित करने जा रहा है। जब आप this.hey..लाइन पर पहुँचते हैं , तो thisइसे बदल दिया जाता है a1और आपको यह मिल जाता है:

a1.hey = function() { alert('from A') }

मैं कवर नहीं करूंगा कि thisबदलाव क्यों होता है a1लेकिन यह अधिक जानने के लिए एक शानदार उत्तर है।

इसलिए संक्षेप में, जब आप करते var a1 = new A()हैं तो पृष्ठभूमि में 3 चीजें हो रही हैं:

  1. एक पूरी तरह से नई खाली वस्तु बनाई और सौंपी गई है a1a1 = {}
  2. a1.__proto__संपत्ति उसी बिंदु पर इंगित करने के लिए निर्दिष्ट की जाती A.prototypeहै (दूसरी खाली वस्तु {})

  3. फ़ंक्शन A()को thisचरण 1 में बनाई गई नई, खाली ऑब्जेक्ट पर सेट के साथ निष्पादित किया जा रहा है (पढ़ें जवाब जो मैंने ऊपर संदर्भित किया है कि क्यों thisबदलता है a1)

अब, चलो एक और वस्तु बनाने की कोशिश करते हैं:

var a2 = new A();

चरण 1,2,3 दोहराएंगे। क्या आप कुछ नोटिस? मुख्य शब्द रिपीट है। चरण 1: a2एक नई खाली वस्तु होगी, चरण 2: इसकी __proto__संपत्ति एक ही बात को इंगित करेगी A.prototypeऔर सबसे महत्वपूर्ण बात, चरण 3: फ़ंक्शन A()फिर से निष्पादित होता है, जिसका अर्थ है कि एक फ़ंक्शन वाली संपत्ति a2प्राप्त होगी heya1और a2दो SEPARATE गुण हैं, heyजो 2 SEPARATE फ़ंक्शन का नाम देते हैं! अब हमारे पास एक ही काम करने वाले दो अलग-अलग ऑब्जेक्ट्स में डुप्लिकेट फ़ंक्शन हैं, उफ़ ... आप इस के मेमोरी निहितार्थों की कल्पना कर सकते हैं यदि हमारे पास 1000 ऑब्जेक्ट्स बनाए गए हैं new A, तो सभी फ़ंक्शंस घोषणाओं के बाद संख्या की तुलना में अधिक मेमोरी लेती हैं। 2. तो हम इसे कैसे रोकें?

याद रखें कि __proto__प्रत्येक वस्तु पर संपत्ति क्यों मौजूद है? ताकि यदि आप उस yoManसंपत्ति को पुनः प्राप्त करते हैं a1(जो मौजूद नहीं है), तो उसकी __proto__संपत्ति से परामर्श किया जाएगा, जो कि अगर यह एक वस्तु है (और यह सबसे अधिक मामले है), तो यह जांच करेगा कि क्या यह शामिल है yoMan, और यदि यह नहीं है यह उस वस्तु के __proto__आदि से परामर्श करेगा । यदि वह ऐसा करता है, तो वह उस संपत्ति का मूल्य लेगा और आपको प्रदर्शित करेगा।

तो किसी ने इस तथ्य + तथ्य का उपयोग करने का फैसला किया कि जब आप बनाते हैं a1, तो इसकी __proto__संपत्ति उसी (खाली) ऑब्जेक्ट को A.prototypeइंगित करती है और ऐसा करती है:

var A = function() {}
A.prototype.hey = function() { alert('from prototype') };

ठंडा! अब, जब आप बनाते हैं a1, यह फिर से ऊपर के सभी 3 चरणों से गुजरता है, और चरण 3 में, यह कुछ भी नहीं करता है, क्योंकि function A()निष्पादित करने के लिए कुछ भी नहीं है। और अगर हम करते हैं:

a1.hey

यह देखेगा कि a1इसमें शामिल नहीं है heyऔर यह देखने के लिए अपनी __proto__संपत्ति वस्तु की जांच करेगा कि क्या यह है, जो कि मामला है।

इस दृष्टिकोण के साथ हम चरण 3 से उस हिस्से को समाप्त करते हैं जहां प्रत्येक नए ऑब्जेक्ट निर्माण पर कार्यों को दोहराया जाता है। इसके बजाय a1और a2एक अलग होने heyसंपत्ति, अब उनमें से कोई भी यह है। जो, मुझे लगता है, तुम अब तक अपने आप को पता लगा। यह अच्छी बात है ... यदि आप समझते हैं __proto__और Function.prototype, इन जैसे प्रश्न बहुत स्पष्ट होंगे।

नोट: कुछ लोग आंतरिक प्रोटोटाइप संपत्ति को कॉल नहीं करते हैं __proto__, मैंने इस नाम को पोस्ट के माध्यम से Functional.prototypeदो अलग-अलग चीजों के रूप में संपत्ति में स्पष्ट रूप से अंतर करने के लिए उपयोग किया है।


1
वास्तव में पूरी तरह से और जानकारीपूर्ण उत्तर। मैंने ऊपर दिए गए ऑब्जेक्ट स्ट्रक्चर्स (A.prototyp.hey vs object this.hey) का उपयोग करके कुछ मेमोरी टेस्ट किए और प्रत्येक के 1000 उदाहरण बनाए। ऑब्जेक्ट प्रॉपर्टी एप्रोच के लिए मेमोरी फुटप्रिंट प्रोटोटाइप की तुलना में लगभग 100kb बड़ा था। फिर मैंने उसी उद्देश्य के साथ एक और फ़ंक्शन जोड़ा, जिसे "मूर्खतापूर्ण" कहा गया और यह 200kb तक रैखिक रूप से बढ़ गया। महत्वपूर्ण नहीं है, लेकिन मूंगफली भी नहीं।
1

क्या अधिक दिलचस्प है कि प्रोटोटाइप विधि स्थानीय रूप से चल रही वस्तु संपत्ति विधि की तुलना में मामूली धीमी थी। कुल मिलाकर, मुझे यकीन नहीं है कि जावास्क्रिप्ट का उपयोग 10k से ऊपर की वस्तुओं की डेटा हेरफेर के लिए किया जाना चाहिए, इसलिए संभावित स्मृति प्रभावों के आधार पर दृष्टिकोण को बदलने के लिए किसी भी कारण की उपेक्षा करना। उस बिंदु पर कार्य सर्वर पर बंद होना चाहिए।

मुद्दा यह है __proto__और .prototypeपूरी तरह से अलग चीजें हैं।
वायऊ

1
मैं तुम्हें सिर्फ एक उत्थान देने के लिए संतुष्ट महसूस नहीं करता ... अच्छा किया!
क्रिस्टियानमितक

58

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

पहले फॉर्म का उपयोग करने का एक कारण "निजी सदस्यों" का उपयोग करना है। उदाहरण के लिए:

var A = function () {
    var private_var = ...;

    this.x = function () {
        return private_var;
    };

    this.setX = function (new_x) {
        private_var = new_x;
    };
};

जावास्क्रिप्ट के डांटने के नियमों के कारण, Private_var इस .x को दिए गए फ़ंक्शन के लिए उपलब्ध है, लेकिन ऑब्जेक्ट के बाहर नहीं।


1
इस पोस्ट को देखें: stackoverflow.com/a/1441692/654708 पर एक उदाहरण के लिए कि प्रोटोटाइप के माध्यम से निजी सदस्यों तक कैसे पहुँचा जाए।
GFoley83

@ GFoley83 का उत्तर यह नहीं दिखाता है कि - प्रोटोटाइप विधियाँ केवल दिए गए ऑब्जेक्ट के "सार्वजनिक" गुणों तक पहुँच सकती हैं। केवल विशेषाधिकार प्राप्त तरीके (प्रोटोटाइप पर नहीं) निजी सदस्यों तक पहुंच सकते हैं।
अलनीतक

27

पहला उदाहरण केवल उस ऑब्जेक्ट के लिए इंटरफ़ेस बदलता है। दूसरा उदाहरण उस वर्ग के सभी ऑब्जेक्ट के लिए इंटरफ़ेस को बदलता है।


दोनों ही फंक्शन xको उन सभी वस्तुओं के लिए उपलब्ध कराएंगे, जिनके प्रोटोटाइप को A का एक नया उदाहरण सौंपा गया है:function B () {}; B.prototype = new A(); var b = new B(); b.x() // Will call A.x if A is defined by first example;
स्पेंसर विलियम्स

21

इसके thisबजाय का उपयोग करने के साथ अंतिम समस्या prototypeयह है कि एक विधि को ओवरराइड करते समय, बेस क्लास का निर्माता अभी भी ओवरराइड विधि का उल्लेख करेगा। इस पर विचार करो:

BaseClass = function() {
    var text = null;

    this.setText = function(value) {
        text = value + " BaseClass!";
    };

    this.getText = function() {
        return text;
    };

    this.setText("Hello"); // This always calls BaseClass.setText()
};

SubClass = function() {
    // setText is not overridden yet,
    // so the constructor calls the superclass' method
    BaseClass.call(this);

    // Keeping a reference to the superclass' method
    var super_setText = this.setText;
    // Overriding
    this.setText = function(value) {
        super_setText.call(this, "SubClass says: " + value);
    };
};
SubClass.prototype = new BaseClass();

var subClass = new SubClass();
console.log(subClass.getText()); // Hello BaseClass!

subClass.setText("Hello"); // setText is already overridden
console.log(subClass.getText()); // SubClass says: Hello BaseClass!

बनाम:

BaseClass = function() {
    this.setText("Hello"); // This calls the overridden method
};

BaseClass.prototype.setText = function(value) {
    this.text = value + " BaseClass!";
};

BaseClass.prototype.getText = function() {
    return this.text;
};

SubClass = function() {
    // setText is already overridden, so this works as expected
    BaseClass.call(this);
};
SubClass.prototype = new BaseClass();

SubClass.prototype.setText = function(value) {
    BaseClass.prototype.setText.call(this, "SubClass says: " + value);
};

var subClass = new SubClass();
console.log(subClass.getText()); // SubClass says: Hello BaseClass!

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

var A = function (param1) {
    var privateVar = null; // Private variable

    // Calling this.setPrivateVar(param1) here would be an error

    this.setPrivateVar = function (value) {
        privateVar = value;
        console.log("setPrivateVar value set to: " + value);

        // param1 is still here, possible memory leak
        console.log("setPrivateVar has param1: " + param1);
    };

    // The constructor logic starts here possibly after
    // many lines of code that define methods

    this.setPrivateVar(param1); // This is valid
};

var a = new A(0);
// setPrivateVar value set to: 0
// setPrivateVar has param1: 0

a.setPrivateVar(1);
//setPrivateVar value set to: 1
//setPrivateVar has param1: 0

बनाम:

var A = function (param1) {
    this.setPublicVar(param1); // This is valid
};
A.prototype.setPublicVar = function (value) {
    this.publicVar = value; // No private variable
};

var a = new A(0);
a.setPublicVar(1);
console.log(a.publicVar); // 1

20

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

prototypeएक फ़ंक्शन कंस्ट्रक्टर की संपत्ति का उपयोग करते समय उस फ़ंक्शन के साथ बनाए गए सभी उदाहरणों के प्रोटोटाइप ऑब्जेक्ट को संदर्भित करता है new


अपने पहले उदाहरण में, आप फ़ंक्शन xके साथ बनाए गए प्रत्येक उदाहरण में एक संपत्ति जोड़ रहे हैं A

var A = function () {
    this.x = function () {
        //do something
    };
};

var a = new A();    // constructor function gets executed
                    // newly created object gets an 'x' property
                    // which is a function
a.x();              // and can be called like this

दूसरे उदाहरण में आप प्रोटोटाइप ऑब्जेक्ट में एक संपत्ति जोड़ रहे हैं जो Aबिंदु के साथ बनाए गए सभी उदाहरण हैं ।

var A = function () { };
A.prototype.x = function () {
    //do something
};

var a = new A();    // constructor function gets executed
                    // which does nothing in this example

a.x();              // you are trying to access the 'x' property of an instance of 'A'
                    // which does not exist
                    // so JavaScript looks for that property in the prototype object
                    // that was defined using the 'prototype' property of the constructor

अंत में, पहले उदाहरण में फ़ंक्शन की एक प्रति प्रत्येक उदाहरण को सौंपी जाती है । दूसरे उदाहरण में फ़ंक्शन की एक एकल प्रतिलिपि सभी उदाहरणों द्वारा साझा की जाती है


1
प्रश्न का सबसे सीधा-सीधा उत्तर होने के लिए इसे वोट किया।
निक पिनेडा

1
मैं अपने सीधे आगे दृष्टिकोण पसंद आया !! अंगूठे ऊपर!
प्रिंस विजय प्रताप

16

क्या फर्क पड़ता है? => बहुत कुछ।

मुझे लगता है, thisएन्कैप्सुलेशन को सक्षम करने के लिए संस्करण का उपयोग किया जाता है, अर्थात डेटा छिपाना। यह निजी चरों में हेरफेर करने में मदद करता है।

आइए हम निम्नलिखित उदाहरण देखें:

var AdultPerson = function() {

  var age;

  this.setAge = function(val) {
    // some housekeeping
    age = val >= 18 && val;
  };

  this.getAge = function() {
    return age;
  };

  this.isValid = function() {
    return !!age;
  };
};

अब, prototypeसंरचना को निम्नलिखित के रूप में लागू किया जा सकता है:

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

AdultPerson.prototype.getRights = function() {
  // Should be valid
  return this.isValid() && ['Booze', 'Drive'];
};

अब कार्यान्वयन को देखते हैं।

var p1 = new AdultPerson;
p1.setAge(12); // ( age = false )
console.log(p1.getRights()); // false ( Kid alert! )
p1.setAge(19); // ( age = 19 )
console.log(p1.getRights()); // ['Booze', 'Drive'] ( Welcome AdultPerson )

var p2 = new AdultPerson;
p2.setAge(45);    
console.log(p2.getRights()); // The same getRights() method, *** not a new copy of it ***

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


3
+1 अन्य की तुलना में बहुत कम जटिल और अधिक ग्राफिकल उत्तर। लेकिन आपको इन (अच्छे) उदाहरणों को प्रदान करने से पहले थोड़ा और विस्तार करना चाहिए।
yerforkferchips

1
मुझे यकीन नहीं है कि "यह संस्करण एन्कैप्सुलेशन को सक्षम करने के लिए उपयोग किया जाता है, अर्थात डेटा छुपा रहा है"। यदि किसी फ़ंक्शन के अंदर एक संपत्ति "इस" के रूप में "this.myProperty = ..." के रूप में परिभाषित की जाती है, तो ऐसी संपत्ति "निजी" नहीं है और इसे "नया" का उपयोग करके कक्षा के बाहर की वस्तुओं से एक्सेस किया जा सकता है।
नं।

14

प्रोटोटाइप कक्षा का टेम्पलेट है; जो भविष्य के सभी उदाहरणों पर लागू होता है। जबकि यह वस्तु का विशेष उदाहरण है।


14

मुझे पता है कि यह मौत के लिए उत्तर दिया गया है, लेकिन मैं गति के अंतर का वास्तविक उदाहरण दिखाना चाहूंगा।

वस्तु पर सीधे कार्य

प्रोटोटाइप पर कार्य

यहां हम printक्रोम में एक विधि के साथ 2,000,000 नई वस्तुओं का निर्माण कर रहे हैं । हम प्रत्येक ऑब्जेक्ट को एक सरणी में संग्रहीत कर रहे हैं। printप्रोटोटाइप पर डालने में लगभग 1/2 समय लगता है।


13

मैं आपको एक अधिक व्यापक उत्तर देता हूं जो मैंने जावास्क्रिप्ट प्रशिक्षण पाठ्यक्रम के दौरान सीखा था।

अधिकांश उत्तरों में पहले से ही अंतर का उल्लेख है, अर्थात जब फ़ंक्शन को प्रोटोटाइप करना सभी (भविष्य) उदाहरणों के साथ साझा किया जाता है। जबकि कक्षा में फ़ंक्शन की घोषणा करने से प्रत्येक उदाहरण के लिए एक प्रतिलिपि बनाई जाएगी।

सामान्य तौर पर कोई सही या गलत नहीं है, यह आपकी आवश्यकताओं के आधार पर अधिक स्वाद या डिजाइन निर्णय का मामला है। हालांकि प्रोटोटाइप एक ऐसी तकनीक है जिसका उपयोग ऑब्जेक्ट ओरिएंटेड तरीके से विकसित करने के लिए किया जाता है, जैसा कि मुझे आशा है कि आप इस उत्तर के अंत में देखेंगे।

आपने अपने प्रश्न में दो पैटर्न दिखाए। मैं दो और समझाने की कोशिश करूंगा और अगर प्रासंगिक हो तो मतभेदों को समझाने की कोशिश करूंगा। बेझिझक संपादित करें / विस्तारित करें। सभी उदाहरणों में यह एक कार ऑब्जेक्ट के बारे में है जिसमें एक स्थान है और वह स्थानांतरित कर सकता है।

ऑब्जेक्ट डेकोरेटर पैटर्न

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

var carlike = function(obj, loc) {
    obj.loc = loc;
    obj.move = function() {
        obj.loc++;
    };
    return obj;
};

var amy = carlike({}, 1);
amy.move();
var ben = carlike({}, 9);
ben.move();

कार्यात्मक कक्षाएं

जावास्क्रिप्ट में एक समारोह एक विशेष वस्तु है। आह्वान किए जाने के अलावा, एक फ़ंक्शन किसी अन्य ऑब्जेक्ट की तरह गुणों को संग्रहीत कर सकता है।

इस मामले Carमें एक फ़ंक्शन ( यह भी लगता है कि वस्तु ) है कि आप के रूप में इस्तेमाल किया जा सकता है। इसमें एक संपत्ति है methods(जो कि एक moveफ़ंक्शन के साथ एक ऑब्जेक्ट है )। जब Carआह्वान किया जाता है तो extendफ़ंक्शन को कहा जाता है, जो कुछ जादू करता है, और Carफ़ंक्शन (थिंक ऑब्जेक्ट) को विस्तारित तरीकों के भीतर विस्तारित करता है methods

यह उदाहरण, हालांकि अलग है, सवाल में पहले उदाहरण के सबसे करीब आता है।

var Car = function(loc) {
    var obj = {loc: loc};
    extend(obj, Car.methods);
    return obj;
};

Car.methods = {
    move : function() {
        this.loc++;
    }
};

var amy = Car(1);
amy.move();
var ben = Car(9);
ben.move();

प्रोटोटाइप कक्षाएं

पहले दो पैटर्न साझा तरीकों को परिभाषित करने या निर्माणकर्ता के शरीर में इनलाइन परिभाषित तरीकों का उपयोग करने की तकनीक का उपयोग करने की चर्चा करते हैं। दोनों मामलों में हर उदाहरण का अपना moveकार्य है।

प्रोटोटाइप पैटर्न खुद को एक ही परीक्षा में अच्छी तरह से उधार नहीं देता है, क्योंकि प्रोटोटाइप प्रतिनिधिमंडल के माध्यम से फ़ंक्शन साझा करना प्रोटोटाइप पैटर्न के लिए बहुत ही लक्ष्य है। जैसा कि अन्य ने बताया है, यह एक बेहतर स्मृति पदचिह्न होने की उम्मीद है।

हालांकि यह जानना एक दिलचस्प बात है कि: प्रत्येक prototypeवस्तु के पास एक सुविधा संपत्ति होती है constructor, जो फ़ंक्शन (थिंक ऑब्जेक्ट) पर वापस लौटती है।

अंतिम तीन पंक्तियों के बारे में:

इस उदाहरण में Carकरने के लिए लिंक prototypeवस्तु है, जो के माध्यम से लिंक constructorकरने के लिए Carही है, यानी Car.prototype.constructorहै Carही। यह आपको यह पता लगाने की अनुमति देता है कि किस निर्माता फ़ंक्शन ने एक निश्चित ऑब्जेक्ट बनाया है।

amy.constructorलुकअप विफल हो जाता है और इस प्रकार उसे सौंप दिया जाता है Car.prototype, जिसमें कंस्ट्रक्टर की संपत्ति होती है। और ऐसा amy.constructorहै Car

इसके अलावा, amyएक है instanceof Carinstanceofऑपरेटर यह देखकर काम करता है कि क्या दाहिने ऑपरेटर की प्रोटोटाइप ऑब्जेक्ट ( Car) बाएं ऑपरेटर के प्रोटोटाइप ( amy) श्रृंखला में कहीं भी पाई जा सकती है ।

var Car = function(loc) {
    var obj = Object.create(Car.prototype);
    obj.loc = loc;
    return obj;
};

Car.prototype.move = function() {
        this.loc++;
};

var amy = Car(1);
amy.move();
var ben = Car(9);
ben.move();

console.log(Car.prototype.constructor);
console.log(amy.constructor);
console.log(amy instanceof Car);

कुछ डेवलपर्स शुरुआत में भ्रमित हो सकते हैं। नीचे दिए गए उदाहरण देखें:

var Dog = function() {
  return {legs: 4, bark: alert};
};

var fido = Dog();
console.log(fido instanceof Dog);

instanceofऑपरेटर रिटर्न false, क्योंकि Dogके प्रोटोटाइप में कहीं भी नहीं पाया जा सकता fidoरों प्रोटोटाइप श्रृंखला '। fidoएक साधारण वस्तु है जो एक वस्तु शाब्दिक के साथ बनाई गई है, अर्थात यह केवल प्रतिनिधि है Object.prototype

स्यूडोसैलिकल पैटर्न

यह वास्तव में सरलीकृत रूप में प्रोटोटाइप पैटर्न का सिर्फ एक और रूप है और उदाहरण के लिए जावा में प्रोग्राम करने वालों के लिए अधिक परिचित है, क्योंकि यह newकंस्ट्रक्टर का उपयोग करता है ।

यह वास्तव में प्रोटोटाइप पैटर्न के रूप में ही करता है, यह सिर्फ प्रोटोटाइप पैटर्न के सिंटैक्टिक शुगर ओवरटॉप है।

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

var Car = function(loc) {
    this.loc = loc;
};

Car.prototype.move = function() {
        this.loc++;
};

var amy = new Car(1);
amy.move();
var ben = new Car(9);
ben.move();

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

एक खंड जो प्रोटोटाइप (श्रृंखला) में सामान्य गुणों / विधियों को परिभाषित करता है।

और एक अन्य खंड जहां आप परिभाषाओं को एक दूसरे से अलग करते हैं ( locउदाहरणों में चर)।

यह वही है जो हमें जावास्क्रिप्ट में सुपरक्लास या उपवर्ग जैसी अवधारणाओं को लागू करने की अनुमति देता है।

जोड़ने या संपादित करने के लिए स्वतंत्र महसूस करें। एक बार और पूरा होने पर मैं इसे सामुदायिक विकि बना सकता हूँ।


बहुत गहन पोस्ट को खटखटाने के लिए नहीं, लेकिन मुझे लगा कि OO और प्रोटोटाइपिकल वंशानुक्रम अनिवार्य रूप से विचारों के विभिन्न स्कूल थे।
निक Pineda

वे हैं, लेकिन एक अलग तकनीक / विचारों के साथ "ओओ" कर सकता है, है ना?
Ely

सच में यकीन नहीं। बहुत से लोग कहते हैं कि प्रोटोटाइप दर्शन केवल अलग है और कई लोग इसे ओओ से तुलना करने की कोशिश करते हैं क्योंकि यह विचार का स्कूल है जिसका उपयोग कई लोग करते हैं।
निक पिनेडा

मेरा मतलब है, यदि आप ओओ शैली का अभ्यास करना चाहते हैं और भाषा ऐसी तकनीकों का एक सेट प्रदान करती है जो ऐसा करने में मदद करती हैं, तो यह जरूरी नहीं है कि गलत हो।
Ely

11

मेरा मानना ​​है कि @ मट्टू क्रुमले सही हैं। वे कार्यात्मक रूप से , यदि संरचनात्मक रूप से, समतुल्य नहीं हैं। यदि आप फायरबग का उपयोग उन वस्तुओं को देखने के लिए करते हैं जो उपयोग करके बनाई गई हैं new, तो आप देख सकते हैं कि वे समान हैं। हालाँकि, मेरी प्राथमिकता निम्नलिखित होगी। मैं यह अनुमान लगा रहा हूं कि यह सिर्फ C # / Java में मेरे द्वारा उपयोग की जाने वाली चीज़ों के समान है। यही है, वर्ग को परिभाषित करें, फ़ील्ड, कंस्ट्रक्टर और विधियों को परिभाषित करें।

var A = function() {};
A.prototype = {
    _instance_var: 0,

    initialize: function(v) { this._instance_var = v; },

    x: function() {  alert(this._instance_var); }
};

EDIT का मतलब यह नहीं था कि चर का दायरा निजी था, मैं सिर्फ यह बताने की कोशिश कर रहा था कि मैं अपनी कक्षाओं को जावास्क्रिप्ट में कैसे परिभाषित करता हूं। इसे दर्शाने के लिए परिवर्तनशील नाम को बदल दिया गया है।


2
एक उदाहरण पर _instance_var initializeऔर x methods do not refer to the _instance_var` संपत्ति के रूप में A, लेकिन एक वैश्विक एक के लिए। this._instance_varयदि आप उदाहरण की _instance_varसंपत्ति का उपयोग करना चाहते हैं, तो उपयोग करें A
लीकेनस्टाइन

2
मजेदार बात यह है कि बेनेरी ने ऐसी त्रुटि भी की, जिसे दो साल बाद भी उजागर किया गया है: पी
लेकेनस्टाइन

10

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

मैंने यह दिखाने के लिए एक jsperf को एक साथ रखा। कक्षा को तुरंत करने में लगने वाले समय में एक नाटकीय अंतर है, हालांकि यह वास्तव में केवल प्रासंगिक है यदि आप कई उदाहरण बना रहे हैं।

http://jsperf.com/functions-in-constructor-vs-prototype


8

सांख्यिकीय रूप से टाइप की गई भाषा के बारे में सोचें, चीजें prototypeस्थिर हैं और thisउदाहरण से संबंधित चीजें हैं।

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