चेतावनी: यह एक लंबी पोस्ट है।
चलो इसे सरल रखें। जब भी मैं जावास्क्रिप्ट में एक निर्माता को बुलाता हूं, मैं हर बार नए ऑपरेटर को उपसर्ग करने से बचना चाहता हूं। ऐसा इसलिए है क्योंकि मैं इसे भूल जाता हूं, और मेरा कोड बुरी तरह खराब हो जाता है।
इसके आस-पास का सरल तरीका यह है ...
function Make(x) {
if ( !(this instanceof arguments.callee) )
return new arguments.callee(x);
// do your stuff...
}
लेकिन, मुझे इसकी आवश्यकता है कि वेरिएबल नं। इस तरह की दलीलें ...
m1 = Make();
m2 = Make(1,2,3);
m3 = Make('apple', 'banana');
पहला तात्कालिक उपाय इस तरह से immediate लागू ’विधि प्रतीत होता है…
function Make() {
if ( !(this instanceof arguments.callee) )
return new arguments.callee.apply(null, arguments);
// do your stuff
}
हालांकि यह गलत है - नई वस्तु apply
विधि और हमारे निर्माता को नहीं दी गई है arguments.callee
।
अब, मैं तीन समाधानों के साथ आया हूँ। मेरा सरल सवाल है: जो सबसे अच्छा लगता है। या, यदि आपके पास एक बेहतर तरीका है, तो इसे बताएं।
पहला - eval()
निर्माणकर्ता को कॉल करने वाले जावास्क्रिप्ट कोड को गतिशील रूप से बनाने के लिए उपयोग करें।
function Make(/* ... */) {
if ( !(this instanceof arguments.callee) ) {
// collect all the arguments
var arr = [];
for ( var i = 0; arguments[i]; i++ )
arr.push( 'arguments[' + i + ']' );
// create code
var code = 'new arguments.callee(' + arr.join(',') + ');';
// call it
return eval( code );
}
// do your stuff with variable arguments...
}
दूसरा - प्रत्येक वस्तु में __proto__
संपत्ति होती है जो उसके प्रोटोटाइप ऑब्जेक्ट के लिए एक 'गुप्त' लिंक है। सौभाग्य से यह संपत्ति लेखन योग्य है।
function Make(/* ... */) {
var obj = {};
// do your stuff on 'obj' just like you'd do on 'this'
// use the variable arguments here
// now do the __proto__ magic
// by 'mutating' obj to make it a different object
obj.__proto__ = arguments.callee.prototype;
// must return obj
return obj;
}
तीसरा - यह दूसरे समाधान के समान है।
function Make(/* ... */) {
// we'll set '_construct' outside
var obj = new arguments.callee._construct();
// now do your stuff on 'obj' just like you'd do on 'this'
// use the variable arguments here
// you have to return obj
return obj;
}
// now first set the _construct property to an empty function
Make._construct = function() {};
// and then mutate the prototype of _construct
Make._construct.prototype = Make.prototype;
eval
समाधान अनाड़ी लगता है और "बुराई निकालने" की सभी समस्याओं के साथ आता है।__proto__
समाधान गैर-मानक है और "mIsERY का महान ब्राउज़र" इसका सम्मान नहीं करता है।तीसरा समाधान अत्यधिक जटिल लगता है।
लेकिन उपरोक्त सभी तीन समाधानों के साथ, हम कुछ इस तरह से कर सकते हैं, कि हम अन्यथा नहीं कर सकते ...
m1 = Make();
m2 = Make(1,2,3);
m3 = Make('apple', 'banana');
m1 instanceof Make; // true
m2 instanceof Make; // true
m3 instanceof Make; // true
Make.prototype.fire = function() {
// ...
};
m1.fire();
m2.fire();
m3.fire();
तो प्रभावी रूप से उपरोक्त समाधान हमें "सच" कंस्ट्रक्टर देते हैं जो चर सं। तर्क और आवश्यकता नहीं है new
। इस पर आपका क्या ख्याल है
-- अपडेट करें --
कुछ ने कहा है "बस एक त्रुटि फेंक"। मेरी प्रतिक्रिया है: हम 10+ कंस्ट्रक्टर्स के साथ एक भारी ऐप कर रहे हैं और मुझे लगता है कि अगर कंसोल में त्रुटि संदेशों को फेंकने के बिना हर निर्माणकर्ता उस गलती को "स्मार्टली" हैंडल कर सकता है, तो यह और अधिक बेहतर होगा।
Make()
बिना किया तो यह आपको चेतावनी देगाnew
क्योंकि मेक कैपिटलाइज़्ड है और इस तरह यह मान लिया कि यह एक कंस्ट्रक्टर है
new
? क्योंकि अगर यह बाद की बात है, तो आप शायद गलत साइट पर पूछ रहे हैं। यदि यह पूर्व है, तो आप नई का उपयोग करने और त्रुटियों का इतनी जल्दी पता लगाने के बारे में सुझावों को खारिज नहीं करना चाह सकते हैं ... यदि आपका ऐप वास्तव में "भारी" है, तो आखिरी चीज जो आप चाहते हैं वह कुछ धीमी गति से निर्माण तंत्र है। new
, सभी फ्लैक के लिए, यह बहुत तेज़ है।