Je ne suis pas sûr de la meilleure approche pour gérer la portée de "this" dans TypeScript.
Voici un exemple d'un modèle commun dans le code que je convertis en TypeScript:
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);
Maintenant, je pourrais changer l'appel en ...
$(document).ready(thisTest.run.bind(thisTest));
... ce qui fonctionne. Mais c'est un peu horrible. Cela signifie que le code peut tout compiler et fonctionner correctement dans certaines circonstances, mais si nous oublions de lier la portée, il se cassera.
Je voudrais un moyen de le faire dans la classe, de sorte que lors de l'utilisation de la classe, nous n'ayons pas à nous soucier de la portée de «ceci».
Aucune suggestion?
Mettre à jour
Une autre approche qui fonctionne consiste à utiliser la grosse flèche:
class DemonstrateScopingProblems {
private status = "blah";
public run = () => {
alert(this.status);
}
}
Est-ce une approche valable?
typescript
this
Jonathan Moffatt
la source
la source
Réponses:
Vous avez ici quelques options, chacune avec ses propres compromis. Malheureusement, il n'y a pas de meilleure solution évidente et cela dépendra vraiment de l'application.
Liaison de classe automatique
Comme indiqué dans votre question:
this
contexte au lieu que chaque site d'appel crée une nouvelle fermeture lors de l'appel.this
contextesuper.
Function.bind
Aussi comme indiqué:
Grosse flèche
dans TypeScript (illustrée ici avec quelques paramètres factices pour des raisons explicatives):
la source
Une autre solution qui nécessite une configuration initiale mais qui porte ses fruits avec sa syntaxe invinciblement légère, littéralement à un mot, consiste à utiliser des décorateurs de méthode pour lier des méthodes JIT via des getters.
J'ai créé un référentiel sur GitHub pour présenter une implémentation de cette idée (c'est un peu long à intégrer dans une réponse avec ses 40 lignes de code, commentaires inclus) , que vous utiliseriez aussi simplement que:
Je n'ai encore vu cela mentionné nulle part, mais cela fonctionne parfaitement. De plus, il n'y a pas d'inconvénient notable à cette approche: l'implémentation de ce décorateur - y compris une vérification de type pour la sécurité du type à l'exécution - est triviale et simple, et n'entraîne pratiquement aucune surcharge après l'appel de la méthode initiale.
La partie essentielle est de définir le getter suivant sur le prototype de classe, qui est exécuté immédiatement avant le premier appel:
Source complète
L'idée peut également être poussée un peu plus loin, en faisant cela dans un décorateur de classe à la place, en parcourant les méthodes et en définissant le descripteur de propriété ci-dessus pour chacune d'elles en une seule passe.
la source
Nécromancie.
Il existe une solution simple et évidente qui ne nécessite pas de fonctions fléchées (les fonctions fléchées sont 30% plus lentes), ni de méthodes JIT via des getters.
Cette solution consiste à lier le this-context dans le constructeur.
Vous pouvez écrire une méthode autobind pour lier automatiquement toutes les fonctions dans le constructeur de la classe:
Notez que si vous ne mettez pas la fonction autobind-function dans la même classe qu'une fonction membre, c'est juste
autoBind(this);
et nonthis.autoBind(this);
Et aussi, la fonction autoBind ci-dessus est simplifiée, pour montrer le principe.
Si vous voulez que cela fonctionne de manière fiable, vous devez tester si la fonction est également un getter / setter d'une propriété, car sinon - boom - si votre classe contient des propriétés, c'est.
Comme ça:
la source
Dans votre code, avez-vous simplement essayé de modifier la dernière ligne comme suit?
la source