कॉलबैक को सेटटाइमआउट करने के लिए "यह" संदर्भ पास करें?


250

मैं संदर्भ कैसे पास करूं setTimeout? मैं कॉल करना चाहते हैं this.tip.destroy(), तो this.options.destroyOnHide1000 के बाद एमएस। मैं उसे कैसे कर सकता हूँ?

if (this.options.destroyOnHide) {
     setTimeout(function() { this.tip.destroy() }, 1000);
} 

जब मैं ऊपर की कोशिश करता हूं, thisतो खिड़की को संदर्भित करता है।


4
क्या डुप्लिकेट ध्वज वास्तव में मान्य है? यह प्रश्न वास्तव में पहले पूछा गया था।
सुई ड्रीम

1
if (this.options.destroyOnHide) {setTimeout (function () {this.tip.destest ()) (.bind (यह), 1000); }
जिब्री

जवाबों:


352

EDIT: संक्षेप में, 2010 में जब यह सवाल पूछा गया कि इस समस्या को हल करने का सबसे सामान्य तरीका उस संदर्भ के संदर्भ को सहेजना है जहां setTimeoutफ़ंक्शन कॉल किया गया है, क्योंकि setTimeoutफ़ंक्शन thisको वैश्विक ऑब्जेक्ट की ओर इशारा करते हुए निष्पादित करता है :

var that = this;
if (this.options.destroyOnHide) {
     setTimeout(function(){ that.tip.destroy() }, 1000);
} 

ईएस 5 कल्पना में, उस समय से एक साल पहले जारी किया गया था, इसने bindविधि पेश की , यह मूल उत्तर में नहीं बताया गया क्योंकि यह अभी तक व्यापक रूप से समर्थित नहीं था और आपको इसका उपयोग करने के लिए पॉलीफ़िल की आवश्यकता थी, लेकिन अब यह हर जगह है:

if (this.options.destroyOnHide) {
     setTimeout(function(){ this.tip.destroy() }.bind(this), 1000);
}

bindसमारोह के साथ एक नया समारोह बनाता thisमूल्य पहले से ही भरे।

अब आधुनिक जे एस में, वास्तव में यह समस्या है तीर कार्यों में हल ES6 :

if (this.options.destroyOnHide) {
     setTimeout(() => { this.tip.destroy() }, 1000);
}

एरो फ़ंक्शंस thisका अपना कोई मान नहीं होता है , जब आप इसे एक्सेस करते हैं, तो आप thisएन्कोडिंग लेक्सिकल स्कोप के मान को एक्सेस कर रहे हैं ।

HTML5 ने 2011 में वापस टाइमर का मानकीकरण किया , और आप कॉलबैक फ़ंक्शन में अब तर्क दे सकते हैं:

if (this.options.destroyOnHide) {
     setTimeout(function(that){ that.tip.destroy() }, 1000, this);
}

यह सभी देखें:


3
यह काम करता हैं। मैंने jsbin स्क्रिप्ट के साथ अवधारणा का परीक्षण किया: jsbin.com/etise/7/edit
John K

1
इस कोड में एक अनावश्यक चर (जिसमें फ़ंक्शन-वाइड गुंजाइश है) बनाना शामिल है; यदि आप सही ढंग thisसे फ़ंक्शन में गए हैं, तो आपने इस समस्या को हल किया होगा, नक्शे के लिए (), forEach (), आदि, आदि के लिए, कम कोड, कम सीपीयू साइकिल और कम मेमोरी का उपयोग करके। *** देखें: मिशा रेज़लिन का जवाब।
होल्डऑफ ह्यूंगर

222

फंक्शन रैपर @CMS के साथ तैयार शॉर्टकट (सिन्गनेटिक शुगर) के साथ हैं। (यह मानते हुए कि आप जो संदर्भ चाहते हैं वह नीचे है this.tip।)


ECMAScript 5 ( वर्तमान ब्राउज़र , Node.js) और प्रोटोटाइप .js

यदि आप ECMA-262, 5th संस्करण (ECMAScript 5) या Node.js के साथ संगत ब्राउज़र को लक्षित करते हैं , तो आप उपयोग कर सकते हैं Function.prototype.bindआंशिक कार्यों को बनाने के लिए आप वैकल्पिक रूप से किसी भी फ़ंक्शन तर्क पास कर सकते हैं ।

fun.bind(thisArg[, arg1[, arg2[, ...]]])

फिर से, आपके मामले में, यह कोशिश करें:

if (this.options.destroyOnHide) {
    setTimeout(this.tip.destroy.bind(this.tip), 1000);
}

प्रोटोटाइप (किसी अन्य लाइब्रेरी?) में भी यही कार्यक्षमता लागू की गई है

Function.prototype.bindयदि आप कस्टम बैकवर्ड संगतता चाहते हैं, तो इसे इस तरह लागू किया जा सकता है (लेकिन कृपया नोट देखें)।


ECMAScript 2015 ( कुछ ब्राउज़र , Node.js 5.0.0+)

अत्याधुनिक विकास (2015) के लिए आप वसा तीर फ़ंक्शंस का उपयोग कर सकते हैं , जो ECMAScript 2015 (हार्मनी / ES6 / ES2015) विनिर्देश ( उदाहरण ) का हिस्सा हैं।

एक तीर समारोह अभिव्यक्ति (भी रूप में जाना जाता वसा तीर समारोह ) समारोह भाव की तुलना में एक छोटा वाक्यविन्यास है और lexically बांधता thisमूल्य [...]।

(param1, param2, ...rest) => { statements }

आपके मामले में, यह कोशिश करें:

if (this.options.destroyOnHide) {
    setTimeout(() => { this.tip.destroy(); }, 1000);
}

jQuery

यदि आप पहले से ही jQuery 1.4+ का उपयोग कर रहे हैं, तो किसी फ़ंक्शन के thisसंदर्भ को स्पष्ट रूप से सेट करने के लिए तैयार फ़ंक्शन है।

jQuery.proxy () : एक फ़ंक्शन लेता है और एक नया रिटर्न देता है जिसमें हमेशा एक विशेष संदर्भ होगा।

$.proxy(function, context[, additionalArguments])

आपके मामले में, यह कोशिश करें:

if (this.options.destroyOnHide) {
    setTimeout($.proxy(this.tip.destroy, this.tip), 1000);
}

अंडरस्कोर.जे , लॉश

यह अंडरस्कोर.जे में उपलब्ध है, साथ ही साथ _.bind(...)1 , 2 भी दर्ज है

किसी कार्य को किसी वस्तु से बांधें , जिसका अर्थ है कि जब भी फ़ंक्शन को बुलायाthisजाएगा, तो वस्तुका मूल्यहोगा। वैकल्पिक रूप से, फ़ंक्शन को पूर्व-भरने के लिए तर्क बाँधें, जिसे आंशिक अनुप्रयोग के रूप में भी जाना जाता है।

_.bind(function, object, [*arguments])

आपके मामले में, यह कोशिश करें:

if (this.options.destroyOnHide) {
    setTimeout(_.bind(this.tip.destroy, this.tip), 1000);
}


डिफ़ॉल्ट क्यों नहीं func.bind(context...)? क्या मुझे कुछ याद है?
एतेई

क्या हर बार जब आप इसे बुलाते हैं, तो यह एक नया फंक्शन (जो बाइंड करता है) बनाता रहता है? मेरे पास एक खोज टाइमआउट है जो हर कीप के बाद रीसेट होता है, और ऐसा लगता है जैसे मुझे पुन: उपयोग करने के लिए इस 'बाध्य' पद्धति को कैशिंग करना चाहिए।
त्रियुन्को

@ ट्रायनको: मैं किसी फ़ंक्शन को एक महंगे ऑपरेशन के रूप में बाँधता नहीं देखता, लेकिन यदि आप एक ही बाउंड फ़ंक्शन को कई बार कॉल करते हैं तो आप एक संदर्भ भी रख सकते हैं: var boundFn = fn.bind(this); boundFn(); boundFn();उदाहरण के लिए।
जोएल पुर्रा

30

इंटरनेट एक्सप्लोरर के अलावा अन्य ब्राउज़रों में, आप देरी के बाद फ़ंक्शन को पैरामीटर पास कर सकते हैं:

var timeoutID = window.setTimeout(func, delay, [param1, param2, ...]);

तो, आप यह कर सकते हैं:

var timeoutID = window.setTimeout(function (self) {
  console.log(self); 
}, 500, this);

यह एक स्कोप लुकअप ( thisटाइमआउट / इंटरवल एक्सप्रेशन के बाहर एक चर में कैशिंग) की तुलना में प्रदर्शन के मामले में बेहतर है , और फिर एक क्लोजर बनाकर (उपयोग करके $.proxyया Function.prototype.bind)।

यह IE से काम करने के लिए कोड वेब्सफ्लेशन IE :

/*@cc_on
(function (modifierFn) {
  // you have to invoke it as `window`'s property so, `window.setTimeout`
  window.setTimeout = modifierFn(window.setTimeout);
  window.setInterval = modifierFn(window.setInterval);
})(function (originalTimerFn) {
    return function (callback, timeout){
      var args = [].slice.call(arguments, 2);
      return originalTimerFn(function () { 
        callback.apply(this, args) 
      }, timeout);
    }
});
@*/

1
प्रोटोटाइप चेन का उपयोग करके एक क्लास बनाते समय और आपके तरीके प्रोटोटाइप तरीके होते हैं ... 'बाइंड' ही एक ऐसी चीज है जो इस तरीके को बदल देगी। कॉलबैक के एक पैरामीटर को पास करके, आप फ़ंक्शन में 'यह' क्या है, इसे बदल नहीं सकते हैं, इसलिए इस तरह के एक प्रोटोटाइप फ़ंक्शन को इसके भीतर 'इस' का उपयोग करके नहीं लिखा जा सकता है क्योंकि कोई अन्य प्रोटोटाइप विधि हो सकती है। इससे असंगति पैदा होती है। बाँध वह चीज़ है जो हम वास्तव में चाहते हैं, और उच्च लुकअप प्रदर्शन के लिए इसे 'इस' में बंद किया जा सकता है और इसे एक से अधिक बार बनाने की आवश्यकता नहीं है।
त्रिकोको

3

नोट: यह IE में काम नहीं करेगा

var ob = {
    p: "ob.p"
}

var p = "window.p";

setTimeout(function(){
    console.log(this.p); // will print "window.p"
},1000); 

setTimeout(function(){
    console.log(this.p); // will print "ob.p"
}.bind(ob),1000);

2

यदि आप उपयोग कर रहे हैं underscore, तो आप उपयोग कर सकते हैं bind

उदाहरण के लिए

if (this.options.destroyOnHide) {
     setTimeout(_.bind(this.tip.destroy, this), 1000);
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.