Nie jestem pewien najlepszego podejścia do obsługi określania zakresu „this” w języku TypeScript.
Oto przykład typowego wzorca w kodzie, który konwertuję na 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);
Teraz mogę zmienić połączenie na ...
$(document).ready(thisTest.run.bind(thisTest));
... który działa. Ale to trochę straszne. Oznacza to, że cały kod może się skompilować i działać dobrze w pewnych okolicznościach, ale jeśli zapomnimy powiązać zakres, to się zepsuje.
Chciałbym znaleźć sposób na zrobienie tego w ramach klasy, aby podczas korzystania z klasy nie musieli się martwić o to, do czego odnosi się „to”.
Jakieś sugestie?
Aktualizacja
Innym podejściem, które działa, jest użycie grubej strzałki:
class DemonstrateScopingProblems {
private status = "blah";
public run = () => {
alert(this.status);
}
}
Czy to prawidłowe podejście?
typescript
this
Jonathan Moffatt
źródło
źródło
Odpowiedzi:
Masz tutaj kilka opcji, z których każda ma swoje własne kompromisy. Niestety nie ma oczywistego najlepszego rozwiązania i będzie to naprawdę zależało od aplikacji.
Automatyczne wiązanie klas
Jak pokazano w Twoim pytaniu:
this
kontekst, zamiast tworzenia przez każdą witrynę wywołania nowego zamknięcia po wywołaniu.this
kontekstusuper.
Function.bind
Również jak pokazano:
Strzałka tłuszczu w języku
TypeScript (pokazana tutaj z paroma fikcyjnymi parametrami z powodów wyjaśniających):
źródło
Innym rozwiązaniem, które wymaga pewnej wstępnej konfiguracji, ale opłaca się swoją niezwyciężoną lekką, dosłownie jednowyrazową składnią, jest użycie dekoratorów metod do wiązania metod JIT przez gettery.
Utworzyłem repozytorium na GitHub, aby zaprezentować implementację tego pomysłu (dopasowanie do odpowiedzi z 40 wierszami kodu, w tym komentarzami , jest trochę za długie) , którego możesz użyć tak prosto, jak:
Nigdzie nie widziałem tego wspomnianego, ale działa bezbłędnie. Nie ma również zauważalnej wady tego podejścia: implementacja tego dekoratora - w tym pewne sprawdzanie typu pod kątem bezpieczeństwa typów w czasie wykonywania - jest trywialna i prosta, a po początkowym wywołaniu metody generuje praktycznie zerowy narzut.
Istotną częścią jest zdefiniowanie następującego gettera na prototypie klasy, który jest wykonywany bezpośrednio przed pierwszym wywołaniem:
Pełne źródło
Pomysł można również pójść o krok dalej, robiąc to w dekoratorze klas, iterując po metodach i definiując powyższy deskryptor właściwości dla każdej z nich w jednym przebiegu.
źródło
Nekromancja.
Istnieje oczywiste proste rozwiązanie, które nie wymaga funkcji strzałkowych (funkcje strzałkowe są o 30% wolniejsze) ani metod JIT poprzez metody pobierające.
Rozwiązaniem jest powiązanie tego kontekstu w konstruktorze.
Możesz napisać metodę autobind, która będzie automatycznie wiązała wszystkie funkcje w konstruktorze klasy:
Zwróć uwagę, że jeśli nie umieścisz funkcji autobind w tej samej klasie co funkcja składowa, to po prostu
autoBind(this);
niethis.autoBind(this);
Ponadto powyższa funkcja autoBind jest przytłumiona, aby pokazać zasadę.
Jeśli chcesz, aby to działało niezawodnie, musisz sprawdzić, czy funkcja jest również pobierającą / ustawiającą właściwości, ponieważ w przeciwnym razie - boom - jeśli twoja klasa zawiera właściwości, to znaczy.
Lubię to:
źródło
Czy w swoim kodzie próbowałeś po prostu zmienić ostatnią linię w następujący sposób?
źródło