Ich bin mir nicht sicher, wie ich das Scoping von "this" in TypeScript am besten handhaben kann.
Hier ist ein Beispiel für ein allgemeines Muster in dem Code, den ich in TypeScript konvertiere:
class DemonstrateScopingProblems {
private status = "blah";
public run() {
alert(this.status);
}
}
var thisTest = new DemonstrateScopingProblems();
// works as expected, displays "blah":
thisTest.run();
// doesn't work; this is scoped to be the document so this.status is undefined:
$(document).ready(thisTest.run);
Jetzt könnte ich den Anruf ändern in ...
$(document).ready(thisTest.run.bind(thisTest));
... was funktioniert. Aber es ist irgendwie schrecklich. Dies bedeutet, dass Code unter bestimmten Umständen kompiliert werden kann und einwandfrei funktioniert. Wenn wir jedoch vergessen, den Bereich zu binden, wird er beschädigt.
Ich möchte eine Möglichkeit, dies innerhalb der Klasse zu tun, damit wir uns bei der Verwendung der Klasse keine Gedanken darüber machen müssen, worauf "dies" abzielt.
Irgendwelche Vorschläge?
Aktualisieren
Ein anderer Ansatz, der funktioniert, ist die Verwendung des Fettpfeils:
class DemonstrateScopingProblems {
private status = "blah";
public run = () => {
alert(this.status);
}
}
Ist das ein gültiger Ansatz?
quelle
Antworten:
Sie haben hier einige Optionen, jede mit ihren eigenen Kompromissen. Leider gibt es keine offensichtlich beste Lösung und es wird wirklich von der Anwendung abhängen.
Automatische Klassenbindung
Wie in Ihrer Frage gezeigt:
this
Kontext zu erfassen, anstatt dass jede Aufrufsite beim Aufrufen einen neuen Abschluss erstellt.this
Kontext zu vergessensuper.
Function.bind
Auch wie gezeigt:
Fetter Pfeil
In TypeScript (hier mit einigen Dummy-Parametern aus erklärenden Gründen gezeigt):
quelle
Eine andere Lösung, die eine anfängliche Einrichtung erfordert, sich jedoch durch ihre unbesiegbar leichte, buchstäblich aus einem Wort bestehende Syntax auszahlt, ist die Verwendung von Method Decorators zum JIT-Binden von Methoden über Getter.
Ich habe auf GitHub ein Repo erstellt , um eine Implementierung dieser Idee zu präsentieren (es ist etwas langwierig, in eine Antwort mit 40 Codezeilen einschließlich Kommentaren zu passen) , die Sie so einfach verwenden würden wie:
Ich habe dies noch nirgendwo erwähnt, aber es funktioniert einwandfrei. Es gibt auch keinen nennenswerten Nachteil bei diesem Ansatz: Die Implementierung dieses Dekorators - einschließlich einiger Typprüfungen zur Laufzeit-Typensicherheit - ist trivial und unkompliziert und verursacht nach dem ersten Methodenaufruf im Wesentlichen keinen Overhead.
Der wesentliche Teil besteht darin, den folgenden Getter für den Klassenprototyp zu definieren, der unmittelbar vor dem ersten Aufruf ausgeführt wird:
Vollständige Quelle
Die Idee kann auch noch einen Schritt weiter gehen, indem Sie dies stattdessen in einem Klassendekorateur tun, Methoden durchlaufen und den obigen Eigenschaftsdeskriptor für jede von ihnen in einem Durchgang definieren.
quelle
Nekromantie.
Es gibt eine offensichtliche einfache Lösung, die keine Pfeilfunktionen (Pfeilfunktionen sind 30% langsamer) oder JIT-Methoden durch Getter erfordert.
Diese Lösung besteht darin, den this-Kontext im Konstruktor zu binden.
Sie können eine Autobind-Methode schreiben, um alle Funktionen im Konstruktor der Klasse automatisch zu binden:
Beachten Sie, dass wenn Sie die Autobind-Funktion nicht in dieselbe Klasse wie eine Member-Funktion einfügen, dies gerecht ist
autoBind(this);
und nichtthis.autoBind(this);
Außerdem wird die obige AutoBind-Funktion heruntergefahren, um das Prinzip zu zeigen.
Wenn dies zuverlässig funktionieren soll, müssen Sie testen, ob die Funktion auch ein Getter / Setter einer Eigenschaft ist, da andernfalls - boom - Ihre Klasse Eigenschaften enthält.
So was:
quelle
Haben Sie in Ihrem Code versucht, die letzte Zeile wie folgt zu ändern?
quelle