श्रृंखला 2. प्रोटोटाइप वंशानुक्रम के संशोधन में पूर्वजों के तरीकों को कैसे लागू किया जाए

छवि आइए हम habrahabr.ru/blogs/javascript/130495 में एक सुविधाजनक .inherit4 विधि को Constr कंस्ट्रक्टर के रूप में बनाना शुरू करते हैं जो वास्तव में कक्षाओं और वंशानुक्रम का एक मॉडल तैयार करता है (यह शास्त्रीय एक से अधिक होगा, लेकिन यह एक साइड इफेक्ट है)। यदि आप Mootools को एक समान मॉडल के साथ जोड़ना नहीं चाहते हैं, तो असम्पीडित कोड की यह 2 KB विधि प्रोटोटाइप इनहेरिटेंस के साथ ठीक से काम करने के लिए पर्याप्त होगी और अतिरिक्त तरीकों की एक जोड़ी होगी: पूर्वजों के तरीकों तक पहुंच। .estestor ('method_name', ancestor_generation संख्या ) और हैश एक्सटेंशन। सभी 3 विधियों का उपयोग करने से आप शब्द को प्रोटोटाइप और कंस्ट्रक्टर को लेक्सिकॉन से बाहर करने की अनुमति देते हैं, दोनों के साथ काम करना जारी रखते हैं, और कोड को पढ़ने में आसान बनाते हैं।

भाग 1 में, 2 कार्यों पर, हमने एक विचार का कार्यान्वयन किया, जिसका उपयोग किया जा सकता है, लेकिन मैं भविष्य के कोड की गुणवत्ता में सुधार करना चाहूंगा। सुधार की कामना:

1) विरासत पेड़ लिखते समय कोड के लेखन और पठनीयता में सुधार - विशेष रूप से, एक वर्ग (अब यह एक फ़ंक्शन है) के रूप में एक वस्तु अभिनय की विधि के माध्यम से विरासत लिखो;
2) इसे सक्षम करने के लिए कंस्ट्रक्टरों के निष्पादन का उपयोग करें। some_method = ... ; (अब उन्हें निष्पादित नहीं किया जाता है, केवल प्रोटोटाइप काम करते हैं, इसलिए विधियों का पारंपरिक निर्माण उपलब्ध नहीं है);
3) निर्माता के प्रोटोटाइप का विस्तार करने के लिए एक पैरामीटर जोड़ें - हम नियमित रूप से, प्रत्येक विरासत के बाद, नए तरीकों के साथ वंश के प्रोटोटाइप का विस्तार करते हैं; ऑपरेशन को नियमित आधार पर करना आवश्यक है; पिछले लेख में, विस्तार () फ़ंक्शन प्रदान किया गया है;
4) एम्बेड करें। उत्तराधिकारी कंस्ट्रक्टर में। अब हमारे पास एक फ़ंक्शन भी है)।

वास्तव में, हम मुटूलों के संदर्भ में एक क्लास ऑब्जेक्ट प्राप्त करना चाहते हैं, लेकिन पूर्वजों तक पहुंच और वंश के प्रोटोटाइप को लोड करने के लिए नियमित क्रियाएं करते हैं। सामान्य तौर पर, विरासत कोड में सुधार हो रहा है, यह विधि के निर्माण के लक्ष्यों में से एक है।

पहले भाग में पूर्वजों की पहुंच के बारे में एक समृद्ध आलोचना की गई थी, सभी के लिए धन्यवाद, विशेष रूप से लालाकी , एंड्रयूसुमिन । इसकी सामान्य दिशा 1 है) OOP के मूल सिद्धांतों के अनुसार, प्रत्यक्ष पूर्वज को छोड़कर पूर्वजों तक पहुंच की आवश्यकता नहीं है, अन्यथा यह मॉडल के खराब डिजाइन को इंगित करता है और मॉडल को बदलना आवश्यक है। इसके अलावा, 2) यह (constructor_name_name) .prototype._reditor_name.apply (यह, पैरामीटर) के माध्यम से एक्सेस करना आसान है, लेकिन OOP टिप्पणियों को भी नजरअंदाज नहीं किया जाना चाहिए।

जवाब:
1. काफी सही, दूर के पूर्वज तक पहुंचना गलत डिजाइन (लिस्की सिद्धांत) को इंगित करता है, सिवाय इसके कि जब हम जेएस इनहेरिटेंस के प्रोसीस्ट्रियन बिस्तर में एक बहु वंशानुक्रम नोड सम्मिलित करना चाहते हैं - जहां 2 या अधिक वर्ग (निर्माता जुड़े हुए हैं)। और निकटतम माता-पिता तक पहुंच के बारे में, सिद्धांत कहता है कि यह वैध है (इसका उपयोग कैसे करें)। दूसरा डिफ़ॉल्ट पैरामीटर (1) - .ancestor ('विधि') के साथ हमारा फ़ंक्शन इसे सबसे संक्षिप्त रूप में बनाता है।

2. हां, 4 शब्दों के माध्यम से पहुंच है " class.prototyp.method.apply ", केवल 3 अतिरिक्त शब्द एक के बजाय जोड़े जाते हैं: वर्ग का नाम और 2 सेवा वाले, लेकिन ' पूर्वज ' और सापेक्ष नोड संख्या पर्याप्त हैं। दूसरी ओर, जब वंशानुक्रम संरचना का पुनर्निर्माण किया जाता है, तो क्रिया अभिव्यक्ति नहीं बदलती है, और नोड संख्या बदल सकती है।

इस प्रकार, आलोचना किसी को इच्छित पथ को बंद करने के लिए मजबूर नहीं करती है - .कैंसर विधि को पेश करने का उद्देश्य उचित था, हमें प्रस्तुति को पूरा करने और हमारे साथ एक उचित पूर्ण विरासत विधि प्रस्तुत करने की आवश्यकता है। फिर भी, आलोचना महत्वपूर्ण है - यह आपको याद दिलाता है कि आपको तरीकों को निष्पादित करने के लिए अनावश्यक पैरामीटर कॉल से बचने की आवश्यकता है, और आदर्श रूप से, केवल अपने तत्काल पूर्वज (इसके लिए .ancestor दूसरे पैरामीटर डिफ़ॉल्ट रूप से = 1) का संदर्भ देते हुए या सामान्य रूप से पूर्वजों का संदर्भ देते हुए।

फ़ंक्शन को फ़ंक्शन के लिए एक विधि बनाना


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

एक उदाहरण से लिंक करें (काम और तरीकों को देखने के लिए फायरबग का उपयोग करना सुविधाजनक है)।

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

बेस फंक्शन ऑब्जेक्ट को ओवरलोड किए बिना समाधान


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

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

चित्रों में निहित


यहाँ यह स्पष्ट है कि बहुक्रियाशील कोड को समझना मुश्किल है, इसलिए, वंशानुक्रम के एक चरण ( .inherit4 () विधि का उपयोग करके) का एक आरेख दिया गया है। मूल रूप से, वह नए कंस्ट्रक्टर को नया ऑपरेशन बनाता है और यह सुनिश्चित करता है कि नए कंस्ट्रक्टर के पास: 1) एक प्रोटोटाइप ( प्रोटोटाइप ), 2) इनहेरिट 4 () फ़ंक्शन है, और प्रोटोटाइप में कम से कम 4 गुण हैं: पूर्वज (फ़ंक्शन), विस्तार (फ़ंक्शन) ), कंस्ट्रक्टर (फ़ंक्शन - स्वयं के लिए एक संदर्भ), _anc (फ़ंक्शन - कंस्ट्रक्टर-माता-पिता के संदर्भ में) और 3) उनके लिए - कंस्ट्रक्टर और उसके प्रोटोटाइप के सभी गुण, और प्रोटोटाइप के गुण अधिक प्राथमिकता हैं और कार्रवाई की आवश्यकता नहीं है। प्रोटोटाइप ( पूर्वज, विस्तार ) के पहले 2 गुणों को भी स्वचालित रूप से कॉपी किया जाता है और कार्रवाई की आवश्यकता नहीं होती है - कोड में कोई प्रतिलिपि नहीं है।



निचला रेखा: वंशानुक्रम कार्य लिखना


/** *        . spmbt, 2011 * @param {Constructor} Inherited - - ( extProto,   ) * @param {Object} extProto -     * @param contextArg0 - 1-     */ var Constr = function(){}; Constr.inherit4 = function(Inherited, extProto, contextArg0){ var f2 ={extend: function(obj, extObj){ //    if(obj ==null) obj = this; if(arguments.length >2) for(var a =1, aL = arguments.length; a < aL; a++) arguments.callee(obj, arguments[a]) else{ if(arguments.length ==1){ extObj = obj; obj = this; } for(var i in extObj) obj[i] = extObj[i]; } return obj; }, ancestor: function(name, level, constr){ //    level = level || (level ==0 ? 0 : 1); var t =this; return level <= 1 ? (level ? constr && constr.prototype[name] || t.constructor.prototype[name] : t[name]) : arguments.callee.call(this, name, level -1 , constr && (constr.prototype._anc != Function && constr.prototype._anc || constr.prototype.constructor) || t._anc ); }}; if(!this.prototype || !this.prototype.ancestor){ if(!this.prototype) this.prototype ={}; for(var i in f2) //       this.prototype[i] = f2[i]; } if(this === Constr && Inherited != Constr){ //   if(Inherited ===null) Inherited = Constr; return arguments.callee.call(Inherited, Inherited, extProto, contextArg0); }else{ if(Inherited || (Inherited && typeof Inherited !='function' && !extProto)){ //   ,   extend + ancestor     if(!extProto){ //  1 -       - extProto = typeof Inherited !='function' ? Inherited :{}; Inherited = typeof Inherited !='function' ? function(){} : Inherited; } Inherited.prototype = new this(contextArg0); Inherited.inherit4 = arguments.callee; f2.extend(Inherited.prototype, {_anc: this, constructor: Inherited}, extProto); return Inherited; }else{ if(this === window) return Constr; else{ this.prototype.constructor = this; return this; //  ,   - } } } }; //: A = Constr.inherit4(function(){this.prop ='A';}, {protoProp:'protoA'}); B = A.inherit4(function(){this.prop ='B';}, {protoProp:'protoB'}); C = B.inherit4(function(arg){this.prop ='C';this.propArg = arg ||'XX';}, {protoProp:'protoC'}); D = C.inherit4(function(arg){this.propArgD = arg ||'XX';}, {protoProp:'protoD'}, '3thArgInCInh'); var c01 = new D('ArgInD'); //B.prototype._anc = B; Alert(c01['protoProp'], c01.ancestor('protoProp', 0), c01.ancestor('prop', 0), c01.prop) //'protoD protoD DD' Alert(c01.constructor.prototype.protoProp, c01.ancestor('protoProp'), c01.ancestor('prop', 1)) //'protoD protoD C' Alert(c01.ancestor('protoProp', 2), c01.ancestor('prop', 2) ); //'protoC B' Alert(c01.ancestor('protoProp', 3), c01.ancestor('prop', 3) ); //'protoB A' Alert(c01.ancestor('protoProp', 4), c01.ancestor('prop', 4) ,'-- prop    ,    '); //'protoA C' Alert(c01.ancestor('protoProp', 5), c01.ancestor('prop', 5) ,'-- protoProp    '); //'protoA C' Alert(c01.ancestor('protoProp', 6), c01.ancestor('prop', 6) ); //'protoA C' Alert(c01.ancestor('protoProp2', 4), c01 instanceof A, c01 instanceof D, '--   - undedfined; instanceof - '); //'undefined D true true' Alert(c01.propArg, '--     C; ', c01.propArgD, '--    D'); 

(नीचे वर्णित कई अतिरिक्त परीक्षणों के साथ एक कामकाजी उदाहरण के लिए , कंसोल देखें (आउटपुट कंसोल में है। क्लॉज ())।)

उपयोग की शर्तें (प्रलेखन के बजाय)


रूट क्लास बनाना:
 _ = Constr.inherit4(function(){_;}, __, 1___); //  ,    //  ,     - {}   _ 

कक्षा में प्रवेश:
 _ = _.inherit4(function(){_;}, ___, 1___); 

एक उदाहरण बनाना - हमेशा की तरह, उदाहरण = नया वर्ग () ;
वंशानुक्रम सूचक - हमेशा की तरह, एक उदाहरण || वर्ग उदाहरण पूर्वज वर्ग ?
// कई वंशानुक्रम के साथ, अगर आप वंशानुक्रम वृक्ष को पंक्तिबद्ध नहीं करते हैं, तो Instof काम नहीं करता है

पूर्वज विधि संदर्भ:
 .ancestor('', _); //   =1 

वर्ग नाम से पूर्वज विधि के लिए संभावित कॉल (कोड, लिंक # में लागू नहीं):
 .ancestor(, '', [__]); 

अतिभारित ऑपरेशन:
-----------------------
अपने आप में एक हैश जोड़ना:
 __Constr.extend(xe); 

अपने आप में कई हैश जोड़ना:
 .extend(null, xe, xe, ...); 

किसी भी हैश का विस्तार:
 _  = __Constr.extend(xe, xe, ...); //  


कथित आलोचना और जवाब


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

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

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

३) पूर्वजों के लिए केवल एक संदर्भअर्ग ० तर्क क्यों है? क्योंकि Inherited.prototype = new (यह (संदर्भ, संदर्भ)) में किसी ऑब्जेक्ट के निर्माण को लिखने का प्रयास ; - काम नहीं करता। लेकिन एक तर्क इसमें सभी मापदंडों के साथ एक हैश सेट करने के लिए पर्याप्त होगा - लगभग तर्कों के समान और अधिक सुविधाजनक विवरण।

4) क्यों एक अतिरिक्त इकाई अगर (यह === खिड़की) ... ? अतिभारित हैश एक्सटेंशन विधि के लिए (खाली 1 तर्क के साथ या 1 तर्क के साथ)। जब वंशानुक्रम का उपयोग नहीं किया जाता है।

कंस्ट्रक्टर तर्क का उपयोग करना


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

उपयोग का प्रदर्शन उदाहरण में है। कक्षा सी में, हमने एक फ़ंक्शन को परिभाषित किया जो पहला तर्क लेता है - हम इसके लिए पहला तर्क C.inherit4 () में तीसरे तर्क के स्थान पर लिखते हैं । कक्षा डी में , एक समान फ़ंक्शन को परिभाषित किया गया था - एक उदाहरण उत्पन्न करने में, तर्क का उपयोग पहले स्थान पर किया जाता है।

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

कंस्ट्रक्टर तर्क इस गुण पर हैश को स्वचालित रूप से फैलाने के लिए फ़ंक्शन को भीख माँगता है:

 function(arg){ //   if( typeof arg =='object') //    for(var i in arg) this[i] = arg[i]; } 

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

 Inherited.prototype = new this(contextArg0); 

एक्सटेंशन:

 if(typeof contextArg0 =='object'){ Inherited.prototype = contextArg0; f2.extend(Inherited.prototype, new this(contextArg0)); }else Inherited.prototype = new this(contextArg0); 

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

यदि आप असाइनमेंट ऑर्डर स्वैप करते हैं,

  Inherited.prototype = new this(contextArg0); f2.extend(Inherited.prototype, contextArg0); 

हमें कंस्ट्रक्टर प्रॉपर्टीज़ (प्रोटोटाइप की तुलना में उच्च प्राथमिकता), जो कभी-कभी काम में आती है (लेकिन यह आदतों पर एक और भी अधिक खतरनाक प्रयोग है, इसलिए हम भी इसका उल्लेख करेंगे) को प्राथमिकता दें।

परीक्षण और कार्रवाई के तंत्र का विश्लेषण


आप पहले लेख से उदाहरण के साथ परीक्षणों के प्रकार की तुलना कर सकते हैं। लगभग एक ही काम किया जाता है (प्लस निर्माणकर्ताओं का निष्पादन), लेकिन कोड अब इतना ढीला नहीं है, तर्क जगह में गिर गए। यह नए लक्ष्य और कुछ लक्ष्य के लिए आंदोलन के साथ फ़ंक्शन कोड के दूषण का परिणाम है।

उदाहरण में, कंस्ट्रक्टरों के गुणों ने भाग लेना शुरू कर दिया - वे जो " this.xxx " से उत्पन्न होते हैं। परीक्षण के उदाहरण में, हमने ध्यान से A, B, C, D प्रत्येक को अपने स्तर पर रखा। परिणामों में हम पत्रों की भरपाई देखते हैं। यह तर्कसंगत है क्योंकि .estestor प्रोटोटाइप को पुनः प्राप्त करता है ( c01.ancestor ('Prop', 0) को छोड़कर), और प्रोटोटाइप वारिस से उत्पन्न होता है: पूर्वजों की संपत्ति को प्रोटोटाइप में लिखा जाता है। यह पता चला है कि अगला हम देखते हैं: संपत्ति पिछली कक्षा से है, प्रोटोटाइप वर्तमान से है। उदाहरण में केवल c01 उदाहरण में एक प्रोटोटाइप नहीं है (उन्होंने इसे नहीं लिखा था), इसलिए इसे पिछली कक्षा से लिया गया है, इसलिए पहली पंक्ति - "प्रोटो डी" - प्रदर्शित अक्षरों में समान है, और निम्नलिखित में एक ऑफसेट है।

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

संदर्भ द्वारा उदाहरण में काम करने वाले परीक्षण दिखाते हैं कि एकाधिक वंशानुक्रम (अवर) कैसे काम करता है, ओवरलोड तरीके उन वस्तुओं में कैसे काम करते हैं जिनमें पूर्वज कॉन्ट्रास्ट होता है । इसके बारे में - थोड़ा कम।

वंशानुक्रम मॉडल और इसकी विविधताएँ


यदि आप डिजाइनरों और प्रोटोटाइप दोनों के गुणों का उपयोग करते हैं तो यहां कुछ विचित्र विरासत मॉडल है। एक मॉडल शास्त्रीय विरासत से अधिक शक्तिशाली है, और यदि आप करीब से देखते हैं, तो इस एल्गोरिथ्म (यह बहुत 30-लाइन एल्गोरिथ्म) के ढांचे के भीतर, आप शास्त्रीय विरासत के एक एनालॉग को दो से अधिक तरीकों से लागू कर सकते हैं - केवल प्रोटोटाइप के माध्यम से या केवल गुणों के माध्यम से। या वंशानुक्रम "इस क्रम में दोगुनी चरण आवृत्ति के साथ":
  1. बेस क्लास कंस्ट्रक्टर ए का प्रोटोटाइप है (इसके गुणों को वहां प्रोटोटाइप में संग्रहीत किया गया है);
  2. 1 वारिस - कंस्ट्रक्टर ए (2 वारिस के प्रोटोटाइप में संग्रहीत) के गुण;
  3. दूसरा वारिस - कंस्ट्रक्टर बी का प्रोटोटाइप (गुण - यहां, 2 वारिस के प्रोटोटाइप में);
  4. 3 वारिस - कंस्ट्रक्टर बी के गुण (4 वें वारिस के प्रोटोटाइप में संग्रहीत);
  5. ...
बेशक, यह शुद्ध शास्त्रीय विरासत नहीं है, क्योंकि आप किसी भी निर्माता के प्रोटोटाइप को बदल सकते हैं, इसलिए, तुरंत सभी उत्तराधिकारियों के गुणों को बदल सकते हैं। लेकिन, पूर्वजों के गुणों को प्रत्येक कक्षा में संग्रहीत नहीं किया जाता है (जब तक कि स्क्रिप्ट इंजन में अनुकूलन नहीं होता है), और यदि आप वारिस बनाने के बाद बदलते प्रोटोटाइप की "गलतियों" से बचते हैं, तो आपको "कदमों की दोहरी आवृत्ति" जैसी मोड में भी शास्त्रीय विरासत मिलेगी।

एकाधिक वंशानुक्रम


अनुकूलता कारणों के लिए, यह भी कहा जाना चाहिए कि कई उत्तराधिकार instof ऑपरेशन द्वारा समर्थित नहीं हैं। पैतृक वृक्ष के प्रति उसकी प्रतिक्रिया बनाना केवल पूर्वजों की पंक्ति में एक पेड़ बनाने से संभव है। इसी समय, प्रोटोटाइप के गुणों को मिश्रण करने के साथ inherit4 () में एक विशेष फ़िंट के कारण, यदि यह पहले से मौजूद है, तो आमतौर पर पूर्वजों से शाखाओं का विलय होता है। मिश्रण के साथ कोड उदाहरण में शामिल नहीं है, इसलिए वंशानुक्रम काम नहीं करेगा - प्रोटोटाइप को केवल पिछले पूर्वजों से एक मूल्य प्राप्त होगा।
 1 = Constr.inherit4(function(){this.prop ='prop1'; this.propA ='propA';}, {protoProp:'prot1'}); 2 = Constr.inherit4(function(){this.prop ='prop2';});  = 1.inherit4({protoProp:'prot11', protoPropA:'protA'});  = 2.inherit4(, {protoProp:'prot2'}); 

सही परिणाम वंशानुक्रम की " पूर्वज 1-पूर्वज 2-वारिस " श्रृंखला में विलय के पेड़ का संरेखण है - मामला जब 1 से अधिक पीढ़ी वाले पूर्वजों के तरीकों तक पहुंचने का एक तरीका काम में आता है।

दोहरी विरासत की गति कहां लागू की जा सकती है?


जहां विरासत की संरचना निर्धारित की जाती है और प्रत्येक स्तर के लिए हम जानते हैं कि क्या लिखना है। उदाहरण के लिए, प्रोग्राम की डिफ़ॉल्ट सेटिंग्स (बेस क्लास) का उपयोग करने का कार्य है, जो "अनुशंसित सेटिंग्स" द्वारा अवरुद्ध हैं, जिन्हें "प्राथमिकता अनुशंसित" द्वारा अवरुद्ध किया गया है, जो अंततः उपयोगकर्ता सेटिंग्स द्वारा अवरुद्ध हैं। कुल - सेटिंग्स के 4 स्तरों में, हर जगह - विरासत संबंध। जाहिर है, जेएस में उन्हें 2 कंस्ट्रक्टरों द्वारा लागू किया जा सकता है और वर्णित प्रकार की विरासत।

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

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

गुणों का विस्तार - "जनता" में विस्तार का वर्णन, और दूसरों की संख्या को खींचकर


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

2) ... और, एह, टहलने के लिए जाने के लिए - तो टहलने के लिए जाने के लिए, हम खुद को विस्तारित करने की संभावना को बढ़ाते हैं यदि एक तर्क लिखा है या यदि पहला तर्क शून्य है

3) एक अतिरिक्त सुविधा - हम (रचनाकार) .inherit4 () , तर्कों के बिना, प्रोटोटाइप में विस्तार और पूर्वज कार्यों दोनों को शामिल करने के लिए कर सकते हैं, अगर हम इस वर्ग (निर्माता) को विरासत में नहीं लेने जा रहे हैं। (ऑब्जेक्ट) .ancestor ('method_name') भी समझ में आएगा अगर जेनरेट ऑब्जेक्ट ( ऑब्जेक्ट = नया कंस्ट्रक्टर (); ) को बाद में डायरेक्ट मैशिंग विधि सौंपी गई - कंस्ट्रक्टर का प्रोटोटाइप तरीका (कंस्ट्रक्टर खुद नहीं) "मानव-पठनीय" एक्सेस (साथ में) object.constructor.prototype [नाम] )।

उदाहरण (यह एक ही शब्दों से स्पष्ट होगा):
ध्यान दें कि Function.prototype.inherit3 के लिए एक समान उदाहरण यह भी जानता है कि कैसे, लेकिन अलग तरह से लिखा गया है।

  = Constr.inherit4(null, {a: 333}); //   = new (); //   - .a = 555; //  Alert(.a, .ancestor('a'), "--     "); //    : 333      : Alert(.extend({a:3}, {b:4}, {c:5}), "--      " ); //Object {a=3, b=4, c=5} 

4) यह देखते हुए कि हम पहला तर्क दे रहे हैं, एक अनाम उत्तराधिकारी बनाना संभव है, ताकि बाद में उसे एक नाम दिया जाए (अधिक सही रूप से, उसे एक नाम दिया जाएगा :))।

 //     (  - null) obj = new (Constr.inherit4()); Alert( obj.extend(null, {a:1}, {b:2}) ); //Object { a=1, b=2, _anc=function(), ... 

5) उदाहरणों में, हम पहले से ही भूल गए थे कि लेख के पहले भाग में हमें ऑब्जेक्ट का एक स्पष्ट प्रोटोटाइप लिखना था - अब यह 2 पैरामीटर द्वारा किया जाता है, यह स्पष्ट और सुविधाजनक है:

 A = Constr.inherit4(function(){_ }, {_}); 

इस प्रारूप में:
 A = Function.inherit4(function(){this.prop ='A';}, {protoProp:'protoA'}); 
कोड एक बिखरी हुई संपत्ति की परिभाषा की तुलना में बहुत बेहतर दिखता है।
नतीजतन, हम देखते हैं कि कोड "मांस" हो गया है, लेकिन प्रत्येक अनुभाग बहुत कुशलता से काम करता है।

यह नहीं भूलना चाहिए कि बेस क्लास ऑब्जेक्ट को .extend विधि नहीं सौंपी गई थी , इसलिए यह {x: 2 .extend ({a: 1}) है; - काम नहीं करेगा (बेस क्लास का विस्तार करने से परहेज की लागत)। लेकिन

 Alert( (new (Constr.inherit4(function(){this.x = 2;}) ) ).extend({a:1}); 

- वसीयत (वस्तु {a: 1, x: 2, और कुछ जोड़े} ) दें। (एक बुरा सपना - बेशक, कोई भी ऐसा नहीं करेगा, लेकिन विचार का प्रदर्शन किया जाता है (खुद को विस्तारित करें ) और अधिक विस्तारित कोड के मामले में काम करेगा।) मुख्य बात यह है कि हम कुछ भी नहीं खोते हैं (केवल नाम स्थान भरा हुआ है ), विस्तार फ़ंक्शन पहले से ही था, यह बस पूर्वज की तरह प्रोटोटाइप रूट ऑब्जेक्ट कॉन्ट्रास्ट को सौंपा।

PS यदि कोई व्यक्ति विरासत या उसी के लिए कम से कम एक समान दृष्टिकोण के वर्णन के लिए एक लिंक प्रदान करता है, तो हम सभी बहुत आभारी होंगे - यह जानना दिलचस्प है कि यह दृष्टिकोण कहाँ जाता है।

PS2 क्या दयालुता के बम से छुटकारा पाना आवश्यक है और कैसे?

Source: https://habr.com/ru/post/In130713/


All Articles