दिलचस्प पोस्ट
ए 4 पेपर आकार सेट करने के लिए सीएसएस Xcode 4 – धीमा प्रदर्शन JQuery में एक ही आईडी के कई तत्वों तक पहुंचें एंड्रॉइड डिवाइस पर वाईफ़ाई या 3 जी नेटवर्क की जांच कैसे करें मैं mysqldump से एक डंप फ़ाइल को कैसे पुनर्स्थापित करूं? एआरएम: लिंक रजिस्टर और फ्रेम सूचक एंड्रॉइड: जीपीएस स्थान की एक छवि कैप्चर कैसे करें क्या कोई वस्तु प्रारंभकर्ता का उपयोग करने का कोई लाभ है? नेस्टेड फ़ंक्शंस में पायथन ओवरराइटिंग चर एक्लिप्से द्वारा जार निर्यात करते समय "मुख्य वर्ग की त्रुटि नहीं मिल पाई" त्रुटि सूची में चयनित आइटम से टेक्स्ट को निकालने के लिए कैसे करें 'पूंछ' कमांड के बराबर विंडोज एंड्रॉइड में स्ट्रिंग.एक्सएम से मूल्य कैसे पढ़ें? मैं पायथन में वैज्ञानिक संकेतन को कैसे दबा सकता हूं? NSMutableArray addObject: – : अपरिचित चयनकर्ता को उदाहरण के लिए भेजा गया

जावास्क्रिप्ट प्रोटोटाइप फ़ंक्शंस में "यह" के संदर्भ को संरक्षित करना

मैं सिर्फ प्रोटोटाइप जावास्क्रिप्ट का प्रयोग कर रहा हूं और मुझे यह पता चलने में परेशानी हो रही है कि जब यह दायरा बदलता है, तब प्रोटोटाइप फ़ंक्शन के अंदर से मुख्य ऑब्जेक्ट के this संदर्भ को कैसे संरक्षित किया जाए। मुझे बताएं कि मेरा क्या मतलब है (मैं यहां jQuery का उपयोग कर रहा हूं):

 MyClass = function() { this.element = $('#element'); this.myValue = 'something'; // some more code } MyClass.prototype.myfunc = function() { // at this point, "this" refers to the instance of MyClass this.element.click(function() { // at this point, "this" refers to the DOM element // but what if I want to access the original "this.myValue"? }); } new MyClass(); 

मुझे पता है कि मैं मुख्य ऑब्जेक्ट के संदर्भ को myfunc की शुरुआत में कर कर रख सकता हूं:

 var myThis = this; 

और तब मुख्य ऑब्जेक्ट की संपत्ति का उपयोग करने के लिए myThis.myValue । लेकिन जब मेरे पास MyClass पर प्रोटोटाइप फ़ंक्शंस का एक पूरा समूह होता है तो क्या होता है? क्या मुझे हर एक की शुरूआत में इसके संदर्भ को सहेजना है? लगता है जैसे वहाँ एक क्लीनर रास्ता होना चाहिए। और इस तरह की स्थिति के बारे में:

 MyClass = function() { this.elements $('.elements'); this.myValue = 'something'; this.elements.each(this.doSomething); } MyClass.prototype.doSomething = function() { // operate on the element } new MyClass(); 

उस मामले में, मैं मुख्य ऑब्जेक्ट के साथ एक संदर्भ नहीं बना सकता है var myThis = this; क्योंकि किसी भी doSomething के संदर्भ में this मूल मान भी एक jQuery ऑब्जेक्ट है और एक doSomething ऑब्जेक्ट नहीं है।

मुझे इस बात का सुझाव दिया गया है कि मूल के संदर्भ को पकड़ने के लिए एक वैश्विक चर का उपयोग this , लेकिन यह मेरे लिए एक बहुत बुरा विचार जैसा लगता है मैं वैश्विक नाम स्थान को प्रदूषित नहीं करना चाहता और ऐसा लगता है कि इससे मुझे दो अलग-अलग MyClass ऑब्जेक्ट्स को एक-दूसरे के साथ हस्तक्षेप किए बिना रोकना होगा।

कोई सुझाव? क्या मैं क्या कर रहा हूँ के लिए एक साफ तरीका है? या मेरा पूरा डिजाइन पैटर्न दोषपूर्ण है?

वेब के समाधान से एकत्रित समाधान "जावास्क्रिप्ट प्रोटोटाइप फ़ंक्शंस में "यह" के संदर्भ को संरक्षित करना"

संदर्भ को संरक्षित करने के लिए, bind विधि वास्तव में उपयोगी है, यह अब हाल ही में रिलीज हुई ईसीएमएस्क्रिप्ट 5 वीं संस्करण विशिष्टता का हिस्सा है, इस फ़ंक्शन का कार्यान्वयन सरल है (केवल 8 लाइन लंबा):

 // The .bind method from Prototype.js if (!Function.prototype.bind) { // check if native implementation available Function.prototype.bind = function(){ var fn = this, args = Array.prototype.slice.call(arguments), object = args.shift(); return function(){ return fn.apply(object, args.concat(Array.prototype.slice.call(arguments))); }; }; } 

और आप इसका इस्तेमाल अपने उदाहरण में कर सकते हैं:

 MyClass.prototype.myfunc = function() { this.element.click((function() { // ... }).bind(this)); }; 

एक और उदाहरण:

 var obj = { test: 'obj test', fx: function() { alert(this.test + '\n' + Array.prototype.slice.call(arguments).join()); } }; var test = "Global test"; var fx1 = obj.fx; var fx2 = obj.fx.bind(obj, 1, 2, 3); fx1(1,2); fx2(4, 5); 

इस दूसरे उदाहरण में हम bind के व्यवहार के बारे में और अधिक देख सकते bind

यह मूल रूप से एक नया फ़ंक्शन निर्मित करता है, जो कि फ़ंक्शन संदर्भ ( this मान) को संरक्षित करते हुए, हमारे कार्य को बुलाए जाने के लिए जिम्मेदार होगा, जिसे bind की पहली तर्क के रूप में परिभाषित किया गया है।

बाकी तर्क केवल हमारे कार्य के लिए पारित किए जाते हैं।

इस उदाहरण में ध्यान दें कि फ़ंक्शन fx1 , किसी ऑब्जेक्ट प्रसंग ( obj.method() ) के बिना लागू किया जाता है, बस एक साधारण फ़ंक्शन कॉल के रूप में, इस प्रकार के इनवॉकेशन में, this कीवर्ड के अंदर ग्लोबल ऑब्जेक्ट को देखेंगे, यह सचेत करेगा "वैश्विक परीक्षण"

अब, fx2 नए फ़ंक्शन है जो bind विधि से उत्पन्न होती है, यह संदर्भ को संरक्षित करने और तर्कों को सही ढंग से पारित करने के लिए हमारे कार्य को कॉल करेगा, यह "ओज टेस्ट 1, 2, 3, 4, 5" को चेतावनी देगा क्योंकि हमने इसे जोड़ने का आह्वान किया था दो अतिरिक्त तर्क, यह पहले से ही पहले तीन बाँध था

अपने पिछले MyClass उदाहरण के लिए, आप यह कर सकते हैं:

 var myThis=this; this.elements.each(function() { myThis.doSomething.apply(myThis, arguments); }); 

फ़ंक्शन जो each को पारित किया each , this एक jQuery ऑब्जेक्ट को संदर्भित करता है, जैसा कि आप पहले से जानते हैं। अगर उस समारोह के अंदर आप मेरे से कुछ काम myThis , और उसके बाद उस फ़ंक्शन पर तर्क apply करते हैं , तो तर्क सरणी के साथ (देखें फ़ंक्शन और arguments apply ), तो this myThis in doSomething myThis सेट हो जाएगा

मुझे पता है यह एक पुरानी धागा है, लेकिन मेरे पास एक ऐसा समाधान है जो अधिक सुरुचिपूर्ण है, और इस तथ्य से अलग कुछ कमियां हैं कि यह आम तौर पर नहीं किया जाता है, जैसा मैंने देखा है।

निम्नलिखित को धयान मे रखते हुए:

 var f=function(){ var context=this; } f.prototype.test=function(){ return context; } var fn=new f(); fn.test(); // should return undefined because the prototype definition // took place outside the scope where 'context' is available 

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

स्थानीय वेरिएबल के दायरे के भीतर तरीकों को बनाने के लिए, हमें उन्हें फ़ंक्शन के सदस्य के रूप में सीधे परिभाषित करना और प्रोटोटाइप संदर्भ से छुटकारा पाने की आवश्यकता है:

 var f=function(){ var context=this; this.test=function(){ console.log(context); return context; }; } var fn=new(f); fn.test(); //should return an object that correctly references 'this' //in the context of that function; fn.test().test().test(); //proving that 'this' is the correct reference; 

आपको चिंता हो सकती है कि क्योंकि विधियों को प्रोटोटाइप नहीं बनाया जा रहा है, विभिन्न उदाहरणों में वास्तव में डेटा अलग नहीं हो सकता है प्रदर्शित करने के लिए कि वे हैं, इस पर विचार करें:

 var f=function(val){ var self=this; this.chain=function(){ return self; }; this.checkval=function(){ return val; }; } var fn1=new f('first value'); var fn2=new f('second value'); fn1.checkval(); fn1.chain().chain().checkval(); // returns 'first value' indicating that not only does the initiated value remain untouched, // one can use the internally stored context reference rigorously without losing sight of local variables. fn2.checkval(); fn2.chain().chain().checkval(); // the fact that this set of tests returns 'second value' // proves that they are really referencing separate instances 

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

 fn=new function(val){ var self=this; this.chain=function(){ return self; }; this.checkval=function(){ return val; }; } fn.checkval(); fn.chain().chain().checkval(); 

प्रो की: फ़ंक्शन ऑब्जेक्ट बनाने के लिए इस पद्धति का उपयोग करने के लिए लाभ बहुतायत से हैं

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

कोन: इस विधि का उपयोग करने के लिए कुछ कमियां हैं मैं व्यापक होने का नाटक नहीं करता हूं 🙂

  • क्योंकि विधियों को सदस्य के रूप में परिभाषित किया जाता है और प्रोटोटाइप नहीं – वंशानुक्रम सदस्य परिभाषा के साथ प्राप्त किया जा सकता है, लेकिन प्रोटोटाइप परिभाषा नहीं है। यह वास्तव में गलत है एक ही प्रोटोटाइपिकल विरासत f.constructor.prototype पर अभिनय करके प्राप्त किया जा सकता है।

आप कॉल () का उपयोग करके दायरा सेट कर सकते हैं और () फ़ंक्शन लागू कर सकते हैं

चूंकि आप jQuery का उपयोग कर रहे हैं, यह ध्यान देने योग्य है कि this पहले से ही jQuery के द्वारा बनाए रखा गया है:

 $("li").each(function(j,o){ $("span", o).each(function(x,y){ alert(o + " " + y); }); }); 

इस उदाहरण में, o li प्रतिनिधित्व करता है, जबकि y बाल span प्रतिनिधित्व करता है। और $.click() , आप event वस्तु से दायरा प्राप्त कर सकते हैं:

 $("li").click(function(e){ $("span", this).each(function(i,o){ alert(e.target + " " + o); }); }); 

जहां e.target li प्रतिनिधित्व करता है, और o बाल span प्रतिनिधित्व करता है

एक और समाधान (और jQuery में मेरा पसंदीदा तरीका) 'इस' को पास करने के लिए उपलब्ध ई-डेटा 'jQuery' का उपयोग करना है। तो आप यह कर सकते हैं:

 this.element.bind('click', this, function(e) { e.data.myValue; //e.data now references the 'this' that you want }); 

आप इस ऑब्जेक्ट के संदर्भ बना सकते हैं या आप with (this) विधि के with (this) इसका उपयोग कर सकते हैं। बाद में बहुत उपयोगी होता है जब आपके इवेंट हैंडलर का उपयोग किया जाता है और आपके संदर्भ में पास करने का कोई तरीका नहीं है।

 MyClass = function() { // More code here ... } MyClass.prototype.myfunc = function() { // Create a reference var obj = this; this.element.click(function() { // "obj" refers to the original class instance with (this){ // "this" now also refers to the original class instance } }); }