it-swarm.com.de

Typoskript "this" innerhalb einer Klassenmethode

Ich weiß, dass dies wahrscheinlich schmerzhaft grundlegend ist, aber es fällt mir schwer, meinen Kopf darum zu wickeln.

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

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

}

Es scheint der Fall zu sein, dass ich einen Proxy benötige, also sagen wir mit Jquery

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

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

}

Aus dem Hintergrund von Actionscript 3 bin ich mir jedoch nicht sicher, was hier passiert. Tut mir leid, ich bin nicht sicher, wo Javascript beginnt und TypeScript endet.

updateProxy: () => void

Und ich bin auch nicht davon überzeugt, dass ich das richtig mache. Das Letzte, was ich möchte, ist, dass der größte Teil meiner Klasse eine a() - Funktion hat, auf die mit aProxy() zugegriffen werden muss, da ich das Gefühl habe, dass ich zweimal dasselbe schreibe? es normal?

71
Clark

Wenn Sie möchten, dass this den TypeScript-Code erfasst, geschieht dies über Pfeilfunktionen. Anders zitieren:

Die this in Pfeilfunktionen sind lexikalisch

So nutze ich das gerne zu meinem Vorteil:

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;      
}

Anzeigen im TypeScript-Playground

Sie können sehen, dass im generierten JavaScript this outside der Funktionsaufruf erfasst wird:

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

der Wert this innerhalb des Funktionsaufrufs (der window sein kann) wird also nicht verwendet.

Weitere Informationen: "this in TypeScript verstehen" (4:05) - YouTube

100
basarat

Wenn Sie Ihre Methoden so schreiben, wird "dies" so behandelt, wie Sie es erwarten.

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

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

Eine andere Möglichkeit wäre, 'this' an den Funktionsaufruf zu binden:

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

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

Siehe Seite 72 der TypeScript-Sprachspezifikation https://github.com/Microsoft/TypeScript/blob/master/doc/TypeScript%20Language%20Specification.pdf?raw=true

Pfeilfunktionsausdrücke

Im Beispiel

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

die Verwendung eines Pfeilfunktionsausdrucks bewirkt, dass der Rückruf die gleiche wie die umgebende 'start'-Methode hat. Wenn Sie den Callback als Standardfunktionsausdruck schreiben, müssen Sie den Zugriff darauf manuell arrangieren, indem Sie ihn beispielsweise in eine lokale Variable kopieren:

Dies ist das aktuell erzeugte Javascript:

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

Das Problem tritt auf, wenn Sie eine Funktion als Rückruf übergeben. Bis der Rückruf ausgeführt wurde, könnte sich der Wert von "this" in "Window", dem Steuerelement, das den Rückruf aufruft, oder in etwas anderem geändert haben.

Stellen Sie sicher, dass Sie immer einen Lambda-Ausdruck verwenden, wenn Sie einen Verweis auf die Funktion übergeben, die zurückgerufen werden soll. Beispielsweise

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

Dies kompiliert sich zu so etwas wie

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

Da die Funktion addFile für eine bestimmte Objektreferenz (_this) aufgerufen wird, wird nicht das "this" des Aufrufers verwendet, sondern der Wert von _this.

4
Peter Morris

Kurz gesagt, das Schlüsselwort this verweist immer auf das Objekt, das die Funktion aufgerufen hat.

Da Funktionen in JavaScript nur Variablen sind, können Sie sie weitergeben.

Beispiel:

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

Wenn Sie mit jQuery Folgendes tun:

$.proxy(this.update, this);

Sie überschreiben diesen Kontext. Hinter den Kulissen von jQuery erfahren Sie Folgendes:

$.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
  }
};
2
Kenneth

Sehr spät zur Party, aber ich denke, dass es für zukünftige Besucher dieser Frage sehr wichtig ist, Folgendes zu berücksichtigen:

Die anderen Antworten, einschließlich der akzeptierten, verfehlen einen entscheidenden Punkt:

myFunction() { ... }

und

myFunction = () => { ... }

sind nicht dasselbe "mit der Ausnahme, dass letztere this erfasst".

Die erste Syntax erstellt eine Methode für den Prototyp, während die zweite Syntax eine Eigenschaft für das Objekt erstellt, dessen Wert eine Funktion ist (die auch this erfasst). Sie sehen dies deutlich im transpilierten JavaScript.

Vollständig sein:

myFunction = function() { ... }

wäre das selbe wie die zweite syntax, aber ohne das capturen.

Die Verwendung der Pfeilsyntax in den meisten Fällen behebt das Problem der Bindung an das Objekt, aber es ist nicht dasselbe, und es gibt viele Situationen, in denen Sie eine ordnungsgemäße Funktion für den Prototyp wünschen anstelle einer Immobilie.

In diesen Fällen ist die Verwendung eines Proxys oder .bind() tatsächlich ist die richtige Lösung. (Obwohl die Lesbarkeit leidet.)

Lesen Sie hier mehr (nicht in erster Linie über TypeScript, sondern über die Prinzipien):

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

1
Karim Ayachi