प्रोटोटाइप का उपयोग करने के लिए जब जावास्क्रिप्ट


93

मैं यह समझना चाहूंगा कि जब js में प्रोटोटाइप तरीकों का उपयोग करना उचित है। क्या उन्हें हमेशा इस्तेमाल किया जाना चाहिए? या ऐसे मामले हैं जहां उनका उपयोग करना पसंद नहीं किया जाता है और / या एक प्रदर्शन जुर्माना लगाता है?

Js में namepacing के लिए सामान्य तरीकों पर इस साइट के आसपास की खोज में, ऐसा लगता है कि अधिकांश एक गैर-प्रोटोटाइप आधारित कार्यान्वयन का उपयोग करते हैं: बस किसी ऑब्जेक्ट या फ़ंक्शन ऑब्जेक्ट का उपयोग करके किसी नामस्थान को एन्कैप्सलेट करना।

एक वर्ग-आधारित भाषा से आ रहा है, यह मुश्किल है कि समानताएं खींचने की कोशिश न करें और सोचें कि प्रोटोटाइप "कक्षाएं" की तरह हैं और जिन नामों का उल्लेख मैंने किया है वे स्थिर तरीकों की तरह हैं।

जवाबों:


133

प्रोटोटाइप एक अनुकूलन हैं

उन्हें अच्छी तरह से उपयोग करने का एक बड़ा उदाहरण jQuery लाइब्रेरी है। हर बार जब आप एक jQuery ऑब्जेक्ट प्राप्त करते हैं $('.someClass'), तो उस ऑब्जेक्ट में दर्जनों "तरीके" होते हैं। किसी वस्तु को लौटाकर पुस्तकालय वह हासिल कर सकता है:

return {
   show: function() { ... },
   hide: function() { ... },
   css: function() { ... },
   animate: function() { ... },
   // etc...
};

लेकिन इसका मतलब यह होगा कि मेमोरी में प्रत्येक jQuery ऑब्जेक्ट में दर्जनों नामांकित स्लॉट्स होंगे, जिनमें एक ही तरीके, बार-बार होंगे।

इसके बजाय, उन विधियों को एक प्रोटोटाइप और सभी jQuery ऑब्जेक्ट्स "इनहेरिट" पर परिभाषित किया गया है, ताकि प्रोटोटाइप उन सभी तरीकों को बहुत कम रनटाइम लागत पर प्राप्त कर सके।

JQuery कैसे सही है, इसका एक महत्वपूर्ण हिस्सा यह है कि यह प्रोग्रामर से छिपा हुआ है। यह पूरी तरह से एक अनुकूलन माना जाता है, ऐसा कुछ नहीं है जिसके बारे में आपको पुस्तकालय का उपयोग करते समय चिंता करनी होगी।

जावास्क्रिप्ट के साथ समस्या यह है कि नग्न निर्माण कार्यों के लिए कॉल करने की आवश्यकता होती है ताकि newवे उन्हें याद रख सकें या अन्यथा वे आमतौर पर काम नहीं करते हैं। इसका कोई अच्छा कारण नहीं है। jQuery को एक सामान्य फ़ंक्शन के पीछे उस बकवास को छुपाकर सही हो जाता है $, इसलिए आपको परवाह नहीं है कि ऑब्जेक्ट कैसे कार्यान्वित किए जाते हैं।

ताकि आप आसानी से एक निर्दिष्ट प्रोटोटाइप के साथ एक ऑब्जेक्ट बना सकें, ECMAScript 5 में एक मानक फ़ंक्शन शामिल है Object.create। इसका एक बहुत ही सरल संस्करण इस तरह दिखेगा:

Object.create = function(prototype) {
    var Type = function () {};
    Type.prototype = prototype;
    return new Type();
};

यह सिर्फ एक कंस्ट्रक्टर फ़ंक्शन लिखने और फिर इसे कॉल करने के दर्द का ख्याल रखता है new

आप प्रोटोटाइप से कब बचेंगे?

एक उपयोगी तुलना लोकप्रिय ओओ भाषाओं जैसे कि जावा और सी # के साथ है। ये दो प्रकार की विरासत का समर्थन करते हैं:

  • इंटरफ़ेस विरासत है, जहां आप implementएक interfaceऐसे वर्ग इंटरफ़ेस के हर सदस्य के लिए अपनी अनूठी कार्यान्वयन प्रदान करता है।
  • कार्यान्वयन विरासत है, जहां आप extendएक classहै कि कुछ तरीकों के डिफ़ॉल्ट कार्यान्वयन प्रदान करता है।

जावास्क्रिप्ट में, प्रोटोटाइप विरासत में कार्यान्वयन विरासत का एक प्रकार है । तो उन स्थितियों में जहां (सी # या जावा में) आप डिफ़ॉल्ट व्यवहार प्राप्त करने के लिए एक आधार वर्ग से निकले होंगे, जिसे आप तब ओवरराइड के माध्यम से छोटे संशोधन करते हैं, फिर जावास्क्रिप्ट में, प्रोटोटाइप विरासत में समझ में आता है।

हालाँकि, यदि आप ऐसी स्थिति में हैं जहाँ आपने C # या Java में इंटरफेस का उपयोग किया होगा, तो आपको जावास्क्रिप्ट में किसी विशेष भाषा सुविधा की आवश्यकता नहीं है। इंटरफ़ेस का प्रतिनिधित्व करने वाली किसी चीज़ को स्पष्ट रूप से घोषित करने की आवश्यकता नहीं है, और उस इंटरफ़ेस को "लागू करने" के रूप में वस्तुओं को चिह्नित करने की आवश्यकता नहीं है:

var duck = {
    quack: function() { ... }
};

duck.quack(); // we're satisfied it's a duck!

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

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


1
अच्छे खर्च। तब आप इस बात से सहमत होंगे कि, चूंकि आप प्रोटोटाइप को एक अनुकूलन मानते हैं, तो उनका उपयोग हमेशा आपके कोड को बेहतर बनाने के लिए किया जा सकता है? मैं सोच रहा था कि ऐसे मामले हैं जहां प्रोटोटाइप का उपयोग करने का कोई मतलब नहीं है, या वास्तव में एक प्रदर्शन जुर्माना है।
15

अपने अनुवर्ती में, आप उल्लेख करते हैं कि "यह निर्भर करता है कि आप प्रत्येक प्रकार के कितने उदाहरणों को आवंटित करते हैं"। लेकिन आपके द्वारा संदर्भित उदाहरण प्रोटोटाइप का उपयोग नहीं कर रहा है। एक उदाहरण आवंटित करने की धारणा कहाँ है (क्या आप अभी भी "नया" यहाँ उपयोग कर रहे हैं)? इसके अलावा: कहो कि क्वैक विधि में एक पैरामीटर था - क्या duck.quack (param) के प्रत्येक इनवोकेशन से मेमोरी में एक नई वस्तु का निर्माण होगा (शायद इसका अप्रासंगिक अगर यह एक पैरामीटर है या नहीं)?
opl

3
1. मेरा मतलब था कि अगर बड़ी संख्या में एक प्रकार के बतख होते हैं, तो यह उदाहरण को संशोधित करने के लिए समझ में आएगा ताकि quackफ़ंक्शन एक प्रोटोटाइप में हो, जिसमें कई बतख उदाहरण जुड़े हुए हैं। 2. वस्तु शाब्दिक वाक्य रचना { ... }एक उदाहरण बनाता है (इसके newसाथ उपयोग करने की कोई आवश्यकता नहीं है)। 3. किसी भी फ़ंक्शन को कॉल करने से जेएस मेमोरी में कम से कम एक ऑब्जेक्ट बनने का कारण बनता है - इसे argumentsऑब्जेक्ट कहा जाता है और कॉल में पास किए गए तर्कों को संग्रहीत करता है: developer.mozilla.org/en/JavaScript/Reference/…
डैनियल ईयरविकेन

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

11
+1 jQuery के साथ तुलना मैंने कब और क्यों प्रोटोटाइप का उपयोग करने का पहला स्पष्ट और संक्षिप्त विवरण किया था, जो मैंने पढ़ा है। आपका बहुत बहुत धन्यवाद।
GFoley83

46

यदि आप ऑब्जेक्ट की "गैर-स्थिर" विधि घोषित करना चाहते हैं, तो आपको प्रोटोटाइप का उपयोग करना चाहिए।

var myObject = function () {

};

myObject.prototype.getA = function (){
  alert("A");
};

myObject.getB = function (){
  alert("B");
};

myObject.getB();  // This works fine

myObject.getA();  // Error!

var myPrototypeCopy = new myObject();
myPrototypeCopy.getA();  // This works, too.

@keatsKelleher लेकिन हम केवल thisउदाहरण का उपयोग करके कंस्ट्रक्टर फ़ंक्शन के अंदर विधि को परिभाषित करके ऑब्जेक्ट के लिए एक गैर-स्थैतिक विधि बना सकते हैं this.getA = function(){alert("A")}?
अमृत ​​लबी

17

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

कहते हैं कि आपके पास एक आधार Car()वर्ग / वस्तु है।

function Car() {
    // do some car stuff
}

तब आप कई Car()उदाहरण बनाते हैं ।

var volvo = new Car(),
    saab = new Car();

अब, आप जानते हैं कि प्रत्येक कार को ड्राइव करने, चालू करने आदि की आवश्यकता होगी, बजाय सीधे Car()क्लास में एक विधि संलग्न करने के (जो प्रत्येक उदाहरण के अनुसार मेमोरी लेता है), आप इसके बजाय प्रोटोटाइप के तरीकों को संलग्न कर सकते हैं (केवल विधियाँ बनाकर) एक बार), इसलिए नए volvoऔर दोनों के लिए उन तरीकों का उपयोग करना saab

// just mapping for less typing
Car.fn = Car.prototype;

Car.fn.drive = function () {
    console.log("they see me rollin'");
};
Car.fn.honk = function () {
    console.log("HONK!!!");
}

volvo.honk();
// => HONK!!!
saab.drive();
// => they see me rollin'

2
वास्तव में यह गलत है। volvo.honk () काम नहीं करेगा क्योंकि आपने प्रोटोटाइप ऑब्जेक्ट को पूरी तरह से बदल दिया है, इसे विस्तारित नहीं किया है। यदि आप ऐसा कुछ करना चाहते हैं तो यह आपकी अपेक्षा के अनुरूप काम करेगा: Car.prototype.honk = function () {कंसोल.लॉग ('HONK');} volvo.honk (); // 'HONK'
29er

1
@ 29er - जिस तरह से मैंने इस उदाहरण को लिखा है, आप सही हैं। आदेश मायने रखता है। अगर मैं इस उदाहरण को रखने के लिए था, Car.prototype = { ... }तो new Car()इस jsfiddle में वर्णित के रूप में कॉल करने से पहले आना होगा : jsfiddle.net/mxacA । आपके तर्क के लिए, यह करने का सही तरीका होगा: jsfiddle.net/Embnp । मजेदार बात यह है, मुझे इस सवाल का जवाब याद नहीं है =)
नरकदान

@ शैलटैन आप उसको कंस्ट्रक्टर सेट करके ठीक कर सकते हैं: कार चूंकि आप एक ऑब्जेक्ट शाब्दिक के साथ प्रोटोटाइप संपत्ति को ओवरवोट करते हैं।
जोश बेदो Josh

@ जोश इस बात की ओर इशारा करता है। मैंने अपना उत्तर अपडेट कर दिया है ताकि मैं किसी वस्तु शाब्दिक रूप से प्रोटोटाइप को ओवरराइट न करूँ, क्योंकि यह शुरुआत से होना चाहिए था।
नरकान

12

एक प्रोटोटाइप ऑब्जेक्ट पर फ़ंक्शंस डालें जब आप किसी विशेष प्रकार की ऑब्जेक्ट की बहुत सारी प्रतियां बनाने जा रहे हों और उन्हें सभी को सामान्य व्यवहार साझा करने की आवश्यकता हो। ऐसा करने से, आप प्रत्येक फ़ंक्शन की केवल एक प्रति होने से कुछ मेमोरी बचाएंगे, लेकिन यह केवल सबसे सरल लाभ है।

प्रोटोटाइप ऑब्जेक्ट्स पर तरीकों को बदलना, या तरीकों को जोड़ना, तुरंत संबंधित प्रकार (ओं) के सभी उदाहरणों की प्रकृति को बदल देता है।

अब वास्तव में आप इन सभी चीजों को क्यों करेंगे, यह ज्यादातर आपके स्वयं के एप्लिकेशन डिज़ाइन का एक कार्य है, और क्लाइंट-साइड कोड में आपको जिन चीजों की आवश्यकता है। (एक पूरी अलग कहानी एक सर्वर के अंदर कोड होगी; और अधिक बड़े पैमाने पर "OO" कोड की कल्पना करने के लिए बहुत आसान है।)


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

जैसे @marcel, d'oh ... =)
हेलाटन

@opi हाँ, आप सही हैं - कोई प्रतिलिपि नहीं बनाई गई है। इसके बजाय, प्रोटोटाइप ऑब्जेक्ट पर प्रतीकों (संपत्ति के नाम) प्रत्येक उदाहरण ऑब्जेक्ट के आभासी भागों के रूप में स्वाभाविक रूप से "वहां" होते हैं। एकमात्र कारण है कि लोग परेशान नहीं करना चाहते हैं कि ऐसे मामले होंगे जहां वस्तुएं अल्पकालिक और अलग हैं, या जहां साझा करने के लिए बहुत "व्यवहार" नहीं है।
नुकीले

3

यदि मैं वर्ग आधारित शब्द में समझाता हूं तो व्यक्ति वर्ग है, चलना () प्रोटोटाइप विधि है। इसके बाद ही वॉक () का अस्तित्व होगा, जब आप इसके साथ नई ऑब्जेक्ट को इंस्टेंट करेंगे।

इसलिए यदि आप ऑब्जेक्ट की प्रतियां बनाना चाहते हैं, जैसे कि यू यूअर कई यूजर्स बना सकते हैं प्रोटोटाइप अच्छा समाधान है क्योंकि यह मेमोरी में प्रत्येक ऑब्जेक्ट के लिए फ़ंक्शन की समान कॉपी को साझा / इनहेरिट करके मेमोरी को बचाता है।

जबकि स्थैतिक ऐसे परिदृश्य में महान मदद नहीं है।

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

// its instance method and can access objects data data 
Person.prototype.walk = function(){
alert("person has started walking.");
}
// its like static method
Person.ProcessPerson = function(Person p){
alert("Persons name is = " + p.name);
}

var userOne = new Person();
var userTwo = new Person();

//Call instance methods
userOne.walk();

//Call static methods
Person.ProcessPerson(userTwo);

तो इसके साथ इसके और अधिक उदाहरण विधि की तरह। ऑब्जेक्ट का दृष्टिकोण स्टैटिक तरीकों की तरह है।

https://developer.mozilla.org/en/Introduction_to_Object-Oriented_JavaScript

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