वर स्व = यह?


182

उदाहरण के तरीकों का उपयोग कर के रूप में ईवेंट हैंडलर्स के लिए कॉलबैक के दायरे में परिवर्तन thisसे "मेरा उदाहरण" के लिए "जो कुछ भी बस कॉलबैक कहा जाता है" । तो मेरा कोड इस तरह दिखता है

function MyObject() {
  this.doSomething = function() {
    ...
  }

  var self = this
  $('#foobar').bind('click', function(){
    self.doSomethng()
    // this.doSomething() would not work here
  })
}

यह काम करता है, लेकिन क्या यह करने का सबसे अच्छा तरीका है? यह मुझे अजीब लगता है।


15
यदि selfकोई window.selfवस्तु है, तो आपको उससे बचना चाहिए और यदि आप अपना स्वयं का selfसंस्करण घोषित करना भूल जाते हैं (जैसे किसी कोड को इधर-उधर हिलाना) तो आप उस गलती का उपयोग कर सकते हैं । यह स्पॉट / डिबग के लिए कष्टप्रद हो सकता है। कुछ का उपयोग करने के लिए बेहतर है _this
एलास्टेयर माव


3
से जावास्क्रिप्ट ट्यूटोरियल : "का मान thisजावास्क्रिप्ट में गतिशील है यह निर्धारित किया जाता है जब समारोह है। कहा जाता है , जब यह घोषित किया जाता है।"
डेविड आरआर


बात वैश्विक दायरे में है self === this। इसलिए, selfस्थानीय संदर्भों में समझ में आता है और पैटर्न का पालन कर रहा है।
प्रोग्रामर

जवाबों:


210

यह सवाल jQuery के लिए विशिष्ट नहीं है, लेकिन सामान्य रूप से जावास्क्रिप्ट के लिए विशिष्ट है। मुख्य समस्या यह है कि एम्बेडेड कार्यों में एक चर को "चैनल" कैसे किया जाए। यह उदाहरण है:

var abc = 1; // we want to use this variable in embedded functions

function xyz(){
  console.log(abc); // it is available here!
  function qwe(){
    console.log(abc); // it is available here too!
  }
  ...
};

यह तकनीक एक क्लोजर का उपयोग करने पर निर्भर करती है। लेकिन यह साथ काम नहीं करता है thisक्योंकि thisएक छद्म चर है जो गुंजाइश से गुंजाइश में गतिशील रूप से बदल सकता है:

// we want to use "this" variable in embedded functions

function xyz(){
  // "this" is different here!
  console.log(this); // not what we wanted!
  function qwe(){
    // "this" is different here too!
    console.log(this); // not what we wanted!
  }
  ...
};

हम क्या कर सकते है? इसे कुछ वैरिएबल को असाइन करें और इसे उपनाम के माध्यम से उपयोग करें:

var abc = this; // we want to use this variable in embedded functions

function xyz(){
  // "this" is different here! --- but we don't care!
  console.log(abc); // now it is the right object!
  function qwe(){
    // "this" is different here too! --- but we don't care!
    console.log(abc); // it is the right object here too!
  }
  ...
};

thisइस संबंध में अद्वितीय नहीं है: argumentsअन्य छद्म चर है जिसे उसी तरह से व्यवहार किया जाना चाहिए - अलियासिंग द्वारा।


7
आपको वास्तव में "इस" को फ़ंक्शन कॉल पर बाँधना चाहिए और इसे चारों ओर से पार नहीं करना चाहिए या इसके साथ चर चर
माइकल

10
@michael क्यों है?
क्रिस एंडरसन

@michael आप पाइप, मैप, सबस्क्राइब के अंदर काम कर रहे होंगे ... एक फ़ंक्शन में और कॉलिंग फ़ंक्शंस नहीं, इस मामले में "यह" बदल रहा है, इसलिए चर गुंजाइश समाधान है
स्कैंडर जेनहानी

@SkanderJenhani कि टिप्पणी 8 साल पुरानी है। मेरा जवाब आज बहुत अलग होगा
माइकल

18

हाँ, यह एक सामान्य मानक प्रतीत होता है। कुछ कोडर स्वयं का उपयोग करते हैं, अन्य मेरा उपयोग करते हैं। यह घटना के विपरीत "वास्तविक" ऑब्जेक्ट के संदर्भ के रूप में उपयोग किया जाता है।

यह ऐसा कुछ है जो मुझे वास्तव में प्राप्त करने में थोड़ा समय लगा, यह पहली बार में अजीब लगता है।

मैं आमतौर पर अपनी वस्तु के शीर्ष पर यह अधिकार करता हूं (मेरे डेमो कोड को बहाना - यह किसी भी चीज की तुलना में अधिक वैचारिक है और उत्कृष्ट कोडिंग तकनीक पर कोई सबक नहीं है):

function MyObject(){
  var me = this;

  //Events
  Click = onClick; //Allows user to override onClick event with their own

  //Event Handlers
  onClick = function(args){
    me.MyProperty = args; //Reference me, referencing this refers to onClick
    ...
    //Do other stuff
  }
}

12
var functionX = function() {
  var self = this;
  var functionY = function(y) {
    // If we call "this" in here, we get a reference to functionY,
    // but if we call "self" (defined earlier), we get a reference to function X.
  }
}

संपादित करें: किसी ऑब्जेक्ट के भीतर नेस्टेड फ़ंक्शन आसपास के ऑब्जेक्ट के बजाय वैश्विक विंडो ऑब्जेक्ट पर ले जाता है।


आपको लगता है कि वर्णन क्या var self = thisकरता है, लेकिन यह वह नहीं है जो सवाल पूछ रहा है (सवाल पूछ रहा है कि क्या समस्या का सबसे अच्छा समाधान है)।
क्वेंटिन

3
"मुख्य समस्या यह है कि एम्बेडेड कार्यों में एक चर" चैनल "कैसे किया जाए।" मैं स्वीकृत उत्तर में इस कथन से सहमत हूं। इसके अलावा "उस" अभ्यास में कुछ भी गलत नहीं है। यह बहुत आम है। इसलिए, "कोड मुझे अजीब लग रहा है" के उत्तर के रूप में मैंने यह समझाने के लिए चुना कि यह कैसे काम करता है। मेरा मानना ​​है कि "कोड मुझे अजीब लग रहा है" इस कारण भ्रम से आता है कि यह कैसे काम करता है।
सेरकण

12

यदि आप ES2015 कर रहे हैं या टाइप स्क्रिप्ट और ES5 कर रहे हैं तो आप अपने कोड में एरो फ़ंक्शंस का उपयोग कर सकते हैं और आप उस त्रुटि का सामना नहीं करते हैं और यह आपके उदाहरण में आपके इच्छित गुंजाइश को संदर्भित करता है।

this.name = 'test'
myObject.doSomething(data => {
  console.log(this.name)  // this should print out 'test'
});

5
एक स्पष्टीकरण के रूप में: ES2015 में तीर फ़ंक्शन thisउनके परिभाषित दायरे से कैप्चर करते हैं। सामान्य कार्य परिभाषाएँ ऐसा नहीं करती हैं।
डिफेंस ने

@defnull मुझे नहीं लगता कि यह कुछ खास है। फ़ंक्शंस एक ब्लॉक स्कोप बनाते हैं। इसलिए फंक्शन के बजाय एरो नोटेशन का उपयोग करना आपको एक दायरा बनाने से रोकता है, इसलिए, यह अभी भी बाहरी इस चर का जिक्र करेगा।
निमेशका श्रीमाल

4

इसका एक हल यह है कि आप अपने सभी कॉलबैक को जावास्क्रिप्ट की bindविधि से अपनी वस्तु में बाँध लें ।

आप इसे एक नामित विधि के साथ कर सकते हैं,

function MyNamedMethod() {
  // You can now call methods on "this" here 
}

doCallBack(MyNamedMethod.bind(this)); 

या एक अनाम कॉलबैक के साथ

doCallBack(function () {
  // You can now call methods on "this" here
}.bind(this));

इनका सहारा लेने के बजाय यह दिखाना कि var self = thisआप कैसे thisजावास्क्रिप्ट में व्यवहार के बंधन को समझते हैं और एक बंद संदर्भ पर भरोसा नहीं करते हैं।

इसके अलावा, ES6 में वसा तीर ऑपरेटर मूल रूप से .bind(this)एक अनाम फ़ंक्शन पर कॉलिंग है:

doCallback( () => {
  // You can reference "this" here now
});

व्यक्तिगत रूप से मुझे लगता है कि .bind (यह) केवल अधिक टाइपिंग है, इस संदर्भ को मेरे (या जो भी) में बदल रहा है और फिर इसके बजाय इसका उपयोग करके क्लीनर कोड बनाता है। मोटा तीर भविष्य का थोम है।
davidbuttar

3

मैंने jQuery का उपयोग नहीं किया है, लेकिन प्रोटोटाइप जैसी लाइब्रेरी में आप फ़ंक्शंस को एक विशिष्ट दायरे में बाँध सकते हैं। ताकि आपके दिमाग में आपका कोड इस तरह दिखाई दे:

 $('#foobar').ready('click', this.doSomething.bind(this));

बाइंड विधि एक नया फ़ंक्शन लौटाती है जो आपके द्वारा निर्दिष्ट दायरे के साथ मूल विधि को कॉल करती है।


अनुरूप: $('#foobar').ready('click', this.doSomething.call(this));सही है?
मुअर्स

bindविधि पुराने ब्राउज़र में काम नहीं करता है, इसलिए का उपयोग $.proxyकरने के बजाय विधि।
गुफ़ा

2

सिर्फ इस बात को जोड़कर कि ES6 में एरो फ़ंक्शंस की वजह से आपको ऐसा करने की ज़रूरत नहीं है क्योंकि वे thisवैल्यू कैप्चर करते हैं ।


1

मुझे लगता है कि यह वास्तव में इस बात पर निर्भर करता है कि आप अपने doSomethingकार्य के अंदर क्या करने जा रहे हैं । यदि आप MyObjectइस कीवर्ड का उपयोग करके गुणों तक पहुँचने जा रहे हैं तो आपको इसका उपयोग करना होगा। लेकिन मुझे लगता है कि यदि आप object(MyObject)गुणों का उपयोग करके कोई विशेष काम नहीं कर रहे हैं तो निम्न कोड टुकड़ा भी काम करेगा ।

function doSomething(){
  .........
}

$("#foobar").ready('click', function(){

});
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.