टाइपस्क्रिप्ट "यह" एक वर्ग विधि के अंदर


84

मुझे पता है कि यह संभवतः दर्द मूल है, लेकिन मैं अपने सिर को उसके चारों ओर लपेटने में कठिन समय बिता रहा हूं।

class Main
{
     constructor()
     {
         requestAnimationFrame(this.update);  //fine    
     }

     update(): void
     {
         requestAnimationFrame(this.update);  //error, because this is window
     }

}

ऐसा प्रतीत होता है कि मुझे प्रॉक्सी की आवश्यकता है, इसलिए Jquery का उपयोग करने की अनुमति देता है

class Main
{
     constructor()
     {
         this.updateProxy = $.proxy(this.update, this);
         requestAnimationFrame(this.updateProxy);  //fine    
     }

     updateProxy: () => void
     update(): void
     {
         requestAnimationFrame(this.updateProxy);  //fine
     }

}

लेकिन एक्टीस्क्रिप्ट 3 पृष्ठभूमि से आने वाले, मुझे वास्तव में यकीन नहीं है कि यहां क्या हो रहा है। क्षमा करें, मुझे यकीन नहीं है कि जावास्क्रिप्ट कहाँ से शुरू होती है और टाइपस्क्रिप्ट समाप्त होती है।

updateProxy: () => void

और यह भी, मुझे यकीन नहीं है कि मैं यह अधिकार कर रहा हूं। आखिरी बात जो मैं चाहता हूं कि मेरी कक्षा का अधिकांश भाग आ () फ़ंक्शन के साथ एक्सेस किया जाना चाहिए, aProxy()क्योंकि मुझे लगता है कि मैं एक ही चीज दो बार लिख रहा हूं? क्या यह सामान्य है?


मुझे यह दस्तावेज बहुत मददगार लगा। github.com/Microsoft/TypeScript/wiki/…
rainversion_3

जवाबों:


119

यदि आप चाहते हैं thisकि ऐसा करने का टाइपस्क्रिप्ट तरीका एरो फ़ंक्शंस के माध्यम से हो। एंडर्स उद्धृत करने के लिए:

thisतीर कार्यों में lexically दायरे वाला

यहाँ मैं अपने लाभ के लिए इसका इस्तेमाल करना चाहता हूँ:

class test{
    // Use arrow functions
    func1=(arg:string)=>{
            return arg+" yeah" + this.prop;
    }
    func2=(arg:number)=>{
            return arg+10 + this.prop;
    }       

    // some property on this
    prop = 10;      
}

इसे टाइपस्क्रिप्ट प्लेग्राउंड में देखें

आप देख सकते हैं कि उत्पन्न जावास्क्रिप्ट में फ़ंक्शन कॉल के बाहरthis कैप्चर किया गया है:

var _this = this;
this.prop = 10;
this.func1 = function (arg) {
    return arg + " yeah" + _this.prop;
};

इसलिए thisफंक्शन कॉल के अंदर मूल्य (जो हो सकता है window) का उपयोग नहीं किया जाएगा।

अधिक जानने के लिए: " thisटाइपस्क्रिप्ट में समझ " (4:05) - YouTube


2
यह आवश्यक नहीं है। आप जो सुझाव दे रहे हैं वह मुहावरेदार जावास्क्रिप्ट है, लेकिन टाइपस्क्रिप्ट इसे अनावश्यक बनाता है।
तातियाना रचेवा

1
वर्ग सदस्यों के संदर्भ में तीर फ़ंक्शन का उपयोग कर @TatianaRacheva को टीएस 0.9.1 से पहले अनुमति नहीं दी गई थी (और यह उत्तर उस से पहले था)। नए वाक्यविन्यास के अपडेट किए गए उत्तर :)
basarat

19
आप वीडियो देखना चाहते हैं - बहुत उपयोगी। केवल 5 मिनट
साइमन_वेअर

1
शुक्रिया, @basarat लाइट-बल्ब इस के लिए संदर्भ के लिए चला गया जैसे ही मैंने देखा कि आप अपने वीडियो के माध्यम से तीर फ़ंक्शन का आधा उपयोग करते हैं। मैं आपकी सराहना करता हूं।
सिमोन

1
var _this = this;आपको चुनने के लिए टाइपस्क्रिप्ट खेल के मैदान पर @ एयरोनल्स ES5; चूंकि ES2015 - अंदर के कार्यों - thisका उपयोग _this
स्टेफानो स्पिनुची

19

यदि आप अपने तरीकों को इस तरह लिखते हैं, तो 'यह' आपकी अपेक्षा के अनुरूप व्यवहार किया जाएगा।

class Main
{
    constructor()
    {
        requestAnimationFrame(() => this.update());
    }

    update(): void
    {
        requestAnimationFrame(() => this.update());
    }
}

एक अन्य विकल्प यह होगा कि फ़ंक्शन कॉल में 'इस' को बाँधें:

class Main
{
    constructor()
    {
        requestAnimationFrame(this.update.bind(this));
    }

    update(): void
    {
        requestAnimationFrame(this.update.bind(this));
    }
}

2
मेरे अनुभव में अपडेट फ़ंक्शन इस तरह से परिभाषित किया गया है: अपडेट = () => {...}
शॉन रोवन

मैं टाइपस्क्रिप्ट बहुत उपयोग कर रहा हूं और कई बार आगे और पीछे बदल चुका हूं। फिलहाल, मैं केवल घुंघराले ब्रेसिज़ को शामिल करता हूं अगर यह एक साधारण विधि कॉल से अधिक है। टाइपस्क्रिप्ट + लाइनक (जो ईश्वरीय रूप से है) का उपयोग करते समय, प्रारूप अच्छा है। उदाहरण: Enumerable.From (गिरफ्तार)। कहाँ (ओ => o.id == 123);
joelnet

मुझे लगता है कि यदि आप उस जावास्क्रिप्ट को देखते हैं जो उत्पन्न होती है, तो आप एक महत्वपूर्ण अंतर देखेंगे। यह स्वाद का मामला नहीं है। update = () => {} "var _this = this" संकलन के माध्यम से lexical scoping बनाएंगे, आपका सिंटैक्स नहीं होगा।
शॉन रोवन

1
आपको अपनी टाइपस्क्रिप्ट लाइब्रेरी को अपग्रेड करने की आवश्यकता हो सकती है क्योंकि इसमें "_this" संदर्भ शामिल है। "() => कोड ()" या () => {रिटर्न कोड () का उपयोग करना; } "100% समान जावास्क्रिप्ट कोड को आउटपुट करेगा। यहां आउटपुट है: i.imgur.com/I5J12.png । आप कोड को टाइप
typecriptlang.org/Playground

जाहिरा तौर पर बाँध (यह) खराब हो सकता है क्योंकि यह मूल फ़ंक्शन आर्ग्स पर टाइप सुरक्षा खो देता है
रोबर्ट राजा

6

टाइपस्क्रिप्ट भाषा विनिर्देश के पेज 72 देखें https://github.com/Microsoft/TypeScript/blob/master/doc/TypeScript%20Language%20Specification.pdf?raw=true

एरो फंक्शन एक्सप्रेशन

उदाहरण में

class Messenger {
 message = "Hello World";
 start() {
 setTimeout(() => alert(this.message), 3000);
 }
};
var messenger = new Messenger();
messenger.start();

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

यह वास्तविक उत्पन्न जावास्क्रिप्ट है:

class Messenger {
 message = "Hello World";
 start() {
 var _this = this;
 setTimeout(function() { alert(_this.message); }, 3000);
 }
};

लिंक दुर्भाग्य से टूट गया है
जिमी केन

1
@JimmyKane I ने लिंक अपडेट किया। अजीब तरह से यह डॉक्टर एक साल से अधिक पुराना है और अभी भी उनके होमपेज से संदर्भित है लेकिन महत्वपूर्ण सामग्री जिसका मैंने उत्तर दिया है।
साइमन_वेचर

4

समस्या तब होती है जब आप किसी फ़ंक्शन को कॉलबैक के रूप में पास करते हैं। जब तक कॉलबैक ने "इस" के मूल्य को निष्पादित किया है, तब तक विंडो में परिवर्तन हो सकता है, कॉलबैक को नियंत्रित करने वाला नियंत्रण, या कुछ और।

सुनिश्चित करें कि आप हमेशा उस लंबर अभिव्यक्ति का उपयोग करते हैं जिस बिंदु पर आप फ़ंक्शन को वापस बुलाया जाना चाहते हैं। उदाहरण के लिए

public addFile(file) {
  this.files.push(file);
}
//Not like this
someObject.doSomething(addFile);
//but instead, like this
someObject.doSomething( (file) => addFile(file) );

यह कुछ इस तरह का संकलन करता है

this.addFile(file) {
  this.files.push(file);
}
var _this = this;
someObject.doSomething(_this.addFile);

क्योंकि AddFile फ़ंक्शन को एक विशिष्ट ऑब्जेक्ट संदर्भ (_this) पर बुलाया जा रहा है, यह इनवोक के "इस" का उपयोग नहीं करता है, बल्कि _this के मान का उपयोग करता है।


जब आप कहते हैं कि यह क्या संकलन करता है, तो आप कौन सा दिखा रहे हैं? (तीर का उदाहरण या वह जो सिर्फ विधि ऑब्जेक्ट को पास करता है?)
टीका नैनो

लंबोदर। बस उस कोड के साथ एक टीएस बनाएं और इसे संकलित करें।
पीटर मोरिस

3

पार्टी के लिए बहुत देर हो चुकी है, लेकिन मुझे लगता है कि इस सवाल के भविष्य के आगंतुकों के लिए यह बहुत महत्वपूर्ण है:

स्वीकृत उत्तर सहित अन्य उत्तर, एक महत्वपूर्ण बिंदु याद करते हैं:

myFunction() { ... }

तथा

myFunction = () => { ... }

हैं नहीं "अपवाद कि बाद कैप्चर के साथ एक ही बात this"।

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

पूरा होने के लिए:

myFunction = function() { ... }

वही दूसरा सिंटैक्स भी होगा, लेकिन कैप्चरिंग के बिना।

तो, ज्यादातर मामलों में तीर सिंटैक्स का उपयोग करने से ऑब्जेक्ट के लिए बाध्य करने की आपकी समस्या ठीक हो जाएगी, लेकिन यह एक ही नहीं है और कई स्थितियां हैं जहां आप चाहते हैं कि संपत्ति के बजाय प्रोटोटाइप पर एक उचित फ़ंक्शन हो।

एक प्रॉक्सी का उपयोग या इन मामलों में .bind()वास्तव में है सही समाधान। (हालांकि पठनीयता पीड़ित)

यहां अधिक पढ़ना (टाइपस्क्रिप्ट के बारे में मुख्य रूप से नहीं, लेकिन सिद्धांत खड़े हैं):

https://medium.com/@charpeni/arrow-functions-in-class-properties-might-not-be-as-great-as-we-think-3b3551c440b1

https://ponyfoo.com/articles/binding-methods-to-class-instance-objects


2

संक्षेप में, इस कीवर्ड में हमेशा उस ऑब्जेक्ट का संदर्भ होता है जिसे फ़ंक्शन कहा जाता है।

जावास्क्रिप्ट में, चूंकि फ़ंक्शन केवल चर हैं, आप उन्हें चारों ओर से गुजार सकते हैं।

उदाहरण:

var x = {
   localvar: 5, 
   test: function(){
      alert(this.localvar);
   }
};

x.test() // outputs 5

var y;
y.somemethod = x.test; // assign the function test from x to the 'property' somemethod on y
y.test();              // outputs undefined, this now points to y and y has no localvar

y.localvar = "super dooper string";
y.test();              // outputs super dooper string

जब आप jQuery के साथ निम्नलिखित करें:

$.proxy(this.update, this);

आप जो कर रहे हैं, वह उस संदर्भ से आगे निकल रहा है। पर्दे के पीछे jQuery आपको यह निर्देशित करेगा:

$.proxy = function(fnc, scope){
  return function(){
     return fnc.apply(scope);  // apply is a method on a function that calls that function with a given this value
  }
};

1

इस तरह से करने के बारे में कैसे? "MyClass" के वैश्विक वैरिएबल को घोषित करें और इसे क्लास के कंस्ट्रक्टर में डालें:

var _self: myClass;

class myClass {
    classScopeVar: string = "hello";

    constructor() {
        _self = this;
    }

    alerter() {
        setTimeout(function () {
            alert(_self.classScopeVar)
        }, 500);
    }
}

var classInstance = new myClass();
classInstance.alerter();

नोट: "स्वयं" का उपयोग करना महत्वपूर्ण नहीं है क्योंकि यह पहले से ही एक विशेष अर्थ के रूप में है।


बड़ी समस्या: वर्ग के सभी उदाहरणों में समान रूप से स्वयं काम होता है इसलिए यह काम नहीं करता है।
अस्तरा भालू
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.