2010-09-28 13 views
24

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

क्या मैं जवाब देने के लिए कोशिश कर रहा हूँ निम्न सवालों

  • उत्पादन के लिए उपयोग करने के लिए John Resig's सरल विरासत संरचना सुरक्षित है कर रहे हैं?
  • क्या यह बताने में सक्षम होने का कोई तरीका है कि इसका परीक्षण कैसे किया गया है?
  • Joose इस उद्देश्य के लिए मेरे पास अन्य विकल्प क्या हैं? मुझे एक ऐसे व्यक्ति की आवश्यकता है जो उपयोग में आसान, तेज़ और मजबूत हो। इसे jQuery के साथ संगत होने की भी आवश्यकता है।
+22

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

+0

+1 पॉइंट। मैंने अभी नीचे आलोचना की है, लेकिन वास्तव में 99% वेबसाइटों पर उनके बारे में अधिक संदिग्ध कोड है ... – bobince

+1

प्रारंभ के लिए jQuery ... –

उत्तर

19

हुह। यह मेरे लिए होने की अपेक्षा अधिक जटिल लग रहा है।

वास्तव में अधिक बारीकी से देखकर मैं सुपरक्लास विधि को कॉल करने के लिए this._super() प्रदान करने के साथ वास्तव में अपवाद लेता हूं।

कोड typeof==='function' पर निर्भरता (कुछ वस्तुओं के लिए अविश्वसनीय), Function#toString (अरे, समारोह अपघटन भी अविश्वसनीय है) परिचय है, और निर्णय लेने से आप समारोह शरीर में बाइट्स _super के अनुक्रम का उपयोग किया है कि क्या के आधार पर रैप करने के लिए है कि क्या (भले ही आपने इसे केवल एक स्ट्रिंग में उपयोग किया हो। और यदि आप उदाहरण की कोशिश करते हैं। this['_'+'super'] यह असफल हो जाएगा)।

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

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

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

Function.prototype.makeSubclass= function() { 
    function Class() { 
     if (!(this instanceof Class)) 
      throw 'Constructor function requires new operator'; 
     if ('_init' in this) 
      this._init.apply(this, arguments); 
    } 
    if (this!==Object) { 
     Function.prototype.makeSubclass.nonconstructor.prototype= this.prototype; 
     Class.prototype= new Function.prototype.makeSubclass.nonconstructor(); 
    } 
    return Class; 
}; 
Function.prototype.makeSubclass.nonconstructor= function() {}; 

यह प्रदान करता है: आकस्मिक के खिलाफ

  1. सुरक्षा new गायब है। वैकल्पिक रूप से X() से new X() पर चुपचाप रीडायरेक्ट करना है ताकि new काम न हो। यह एक टॉस-अप है जो सबसे अच्छा है; मैं स्पष्ट त्रुटि के लिए गया ताकि किसी को new के बिना लिखने के लिए उपयोग न किया जाए और अन्य वस्तुओं पर समस्याएं उत्पन्न न हों। this. गुणों को window पर गिरने और रहस्यमय तरीके से गलत होने के बाद अस्वीकार्य जेएस डिफ़ॉल्ट से किसी भी तरह से बेहतर है।

  2. एक विरासत _init विधि, इसलिए आपको एक कन्स्ट्रक्टर-फ़ंक्शन लिखना नहीं है जो सुपरक्लास कन्स्ट्रक्टर फ़ंक्शन को कॉल करने के अलावा कुछ भी नहीं करता है।

और यह वास्तव में सब कुछ है।

var Person= Object.makeSubclass(); 
Person.prototype._init= function(isDancing) { 
    this.dancing= isDancing; 
}; 
Person.prototype.dance= function() { 
    return this.dancing; 
}; 

var Ninja = Person.makeSubclass(); 
Ninja.prototype._init= function() { 
    Person.prototype._init.call(this, false); 
}; 
Ninja.prototype.swingSword= function() { 
    return true; 
}; 

var p= new Person(true); 
p.dance(); // => true 

var n = new Ninja(); 
n.dance(); // => false 
n.swingSword(); // => true 

// Should all be true 
p instanceof Person && 
n instanceof Ninja && n instanceof Person 

सुपर क्लास-बुला विशेष रूप से विधि आप चाहते हैं नामकरण और call यह अजगर की तरह ing, थोड़ा द्वारा किया जाता है:

यहाँ कैसे आप इसका इस्तेमाल कर सकते हैं Resig के उदाहरण को लागू करने की है। _super सदस्य को कन्स्ट्रक्टर फ़ंक्शन में जोड़ सकता है यदि आप Person नामकरण से बचना चाहते हैं (तो आप Ninja._super.prototype._init.call, या शायद Ninja._base._init.call कहेंगे)।

+0

'टाइपोफ' केवल कार्यों के लिए अविश्वसनीय है यदि आप होस्ट ऑब्जेक्ट्स से निपट रहे हैं, और आप उनमें से किसी एक को उपclass नहीं करना चाहते हैं। या कम से कम, आपको नहीं करना चाहिए। मैं निश्चित रूप से सहमत हूं कि रेसिग का कोड अत्यधिक ट्रिक्स और नाजुक है, और इसकी आवश्यकता नहीं है। –

+0

@Tim: हाँ, आप किसी होस्ट ऑब्जेक्ट को प्रोटोटाइप नहीं कर सकते हैं, लेकिन फ़ंक्शन टेस्ट क्या कर रहा है सुपरक्लास ऑब्जेक्ट की बजाय प्रत्येक सदस्य को जांच रहा है। इसलिए आपकी कक्षा का सदस्य होने वाला मेजबान वस्तु समस्याएं पैदा कर सकती है। (उदाहरण के लिए फ़ायरफ़ॉक्स 3.0 में एक regexp फ़ंक्शन के रूप में आता है, इसलिए क्लास.क्स्टेंड में रैपिंग उन्हें फ़ंक्शन की तरह लपेटने की कोशिश करके regexp सदस्यों को nadger कर सकता है)। – bobince

+0

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

5

जावास्क्रिप्ट प्रोटोटाइप आधारित है और कक्षा आधारित नहीं है। मेरी सिफारिश है कि यह लड़ने और जेएसई के उपप्रकारों को घोषित न करें:

MyDerivedObj.prototype = new MySuperObj(); 
MyDerivedObj.prototype.constructor = MyDerivedObj; 
+3

इसके साथ समस्या यह है कि 'नया MySuperObj()' कॉलिंग प्रारंभिक कोड को आमंत्रित करता है 'MySuperObj()' के लिए कन्स्ट्रक्टर फ़ंक्शन, जैसे कि आप वास्तव में 'MySuperObj' को तुरंत चालू कर रहे थे। जैसे ही आपके पास कन्स्ट्रक्टर फ़ंक्शन में कुछ भी मामूली नहीं है, यह काम नहीं करता है, क्योंकि जब आप 'MyDerivedObj' उदाहरण बनाते हैं, तो परिभाषित समय पर' MySuperObj' प्रारंभिक कोड को कॉल करने की आवश्यकता होती है। – bobince

+1

मैं सहमत हूं कि आप अपने प्रारंभिक कोड को एक अलग विधि में कारक बनाना चाहते हैं और इसे MyDerivedObj के निर्माता से कॉल कर सकते हैं ... बेहतर अभी भी निर्भरता इंजेक्शन का उपयोग करने पर विचार करें। मैंने पाया है कि यह कन्स्ट्रक्टर कोड पर एक बड़ा सौदा घटा देता है। –

5

देखें कि आप विरासत का उपयोग किए बिना कितना दूर प्राप्त कर सकते हैं। एक डिजाइन सिद्धांत के बजाय इसे एक प्रदर्शन हैक (अनिच्छुक रूप से लागू करने के लिए) के रूप में व्यवहार करें।

जेएस जैसी अत्यधिक गतिशील भाषा में, यह जानना शायद ही आवश्यक है कि कोई ऑब्जेक्ट Person है। आपको सिर्फ यह जानने की जरूरत है कि मेंfirstName संपत्ति या eatFood विधि है। आपको अक्सर यह जानने की आवश्यकता नहीं होती है कि कोई ऑब्जेक्ट एक सरणी है या नहीं; यदि इसकी लंबाई लंबाई और पूर्णांक के नाम पर कुछ अन्य गुण हैं, तो आमतौर पर यह काफी अच्छा होता है (उदा। तर्क वस्तु)। "अगर यह एक बतख की तरह एक बतख और quacks की तरह चलता है, यह एक बतख है।"

// give back a duck 
return { 
    walk: function() { ... }, 
    quack: function() { ... } 
}; 

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

(और ध्यान दें कि आप वास्तव में उस स्थिति में शास्त्रीय विरासत मॉडलिंग नहीं किया जाएगा। यह केवल एक एकल वर्ग को परिभाषित करने के लिए एक साझा vtable की दक्षता प्राप्त करने के लिए के बराबर है।)

संबंधित मुद्दे