Wiem, że jest to prawdopodobnie boleśnie podstawowe, ale ciężko mi to obejść.
class Main
{
constructor()
{
requestAnimationFrame(this.update); //fine
}
update(): void
{
requestAnimationFrame(this.update); //error, because this is window
}
}
Wygląda na to, że potrzebuję proxy, więc powiedzmy, że używam Jquery
class Main
{
constructor()
{
this.updateProxy = $.proxy(this.update, this);
requestAnimationFrame(this.updateProxy); //fine
}
updateProxy: () => void
update(): void
{
requestAnimationFrame(this.updateProxy); //fine
}
}
Ale wychodząc z tła Actionscript 3, nie jestem pewien, co się tutaj dzieje. Przepraszam, nie jestem pewien, gdzie zaczyna się JavaScript, a kończy TypeScript.
updateProxy: () => void
Nie jestem też przekonany, że robię to dobrze. Ostatnią rzeczą, której chcę, jest to, że większość mojej klasy ma funkcję aa (), do której należy uzyskać dostęp, aProxy()
ponieważ czuję, że piszę to samo dwa razy? Jest to normalne?
jquery
this
typescript
proxy-classes
Clark
źródło
źródło
Odpowiedzi:
Jeśli chcesz
this
uchwycić sposób TypeScript, robi to za pomocą funkcji strzałkowych. Cytując Andersa:Oto sposób, w jaki lubię to wykorzystać na swoją korzyść:
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; }
Zobacz to w TypeScript Playground
Możesz zobaczyć, że w wygenerowanym skrypcie JavaScript
this
jest przechwytywany poza wywołaniem funkcji:var _this = this; this.prop = 10; this.func1 = function (arg) { return arg + " yeah" + _this.prop; };
więc
this
wartość wewnątrz wywołania funkcji (która mogłaby byćwindow
) nie byłaby używana.Więcej informacji: „Understanding
this
in TypeScript” (4:05) - YouTubeźródło
var _this = this;
musisz wybraćES5
; ponieważ ES2015 - funkcje wewnętrzne -this
jest używany zamiast_this
Jeśli napiszesz swoje metody w ten sposób, „to” zostanie potraktowane tak, jak oczekujesz.
class Main { constructor() { requestAnimationFrame(() => this.update()); } update(): void { requestAnimationFrame(() => this.update()); } }
Inną opcją byłoby powiązanie „this” z wywołaniem funkcji:
class Main { constructor() { requestAnimationFrame(this.update.bind(this)); } update(): void { requestAnimationFrame(this.update.bind(this)); } }
źródło
Patrz strona 72 specyfikacji języka maszynopisu https://github.com/Microsoft/TypeScript/blob/master/doc/TypeScript%20Language%20Specification.pdf?raw=true
Wyrażenia funkcyjne strzałek
W przykładzie
class Messenger { message = "Hello World"; start() { setTimeout(() => alert(this.message), 3000); } }; var messenger = new Messenger(); messenger.start();
To jest faktycznie wygenerowany JavaScript:
class Messenger { message = "Hello World"; start() { var _this = this; setTimeout(function() { alert(_this.message); }, 3000); } };
źródło
Problem pojawia się, gdy przekazujesz funkcję jako wywołanie zwrotne. Zanim callback wykona, wartość „this” mogła zmienić się na Window, kontrolkę wywołującą callback lub coś innego.
Upewnij się, że zawsze używasz wyrażenia lambda w momencie przekazywania odniesienia do funkcji, która ma zostać wywołana z powrotem. Na przykład
public addFile(file) { this.files.push(file); } //Not like this someObject.doSomething(addFile); //but instead, like this someObject.doSomething( (file) => addFile(file) );
To kompiluje się do czegoś podobnego
this.addFile(file) { this.files.push(file); } var _this = this; someObject.doSomething(_this.addFile);
Ponieważ funkcja addFile jest wywoływana na podstawie określonego odwołania do obiektu (_this), nie używa ona wartości „this” obiektu wywołującego, ale zamiast tego wartość _this.
źródło
Bardzo późno na imprezę, ale myślę, że dla przyszłych odwiedzających to pytanie bardzo ważne jest rozważenie następujących kwestii:
Pozostałe odpowiedzi, w tym zaakceptowana, pomijają kluczowy punkt:
myFunction() { ... }
i
myFunction = () => { ... }
nie są tym samym, „z wyjątkiem tego, że ten ostatni przechwytuje
this
”.Pierwsza składnia tworzy metodę na prototypie, podczas gdy druga składnia tworzy właściwość na obiekcie, którego wartość jest funkcją (która również jest przechwytywana
this
). Widać to wyraźnie w transpiled JavaScript.Aby być kompletnym:
myFunction = function() { ... }
byłaby taka sama jak druga składnia, ale bez przechwytywania.
Tak więc, użycie składni strzałek w większości przypadków rozwiązuje problem z wiązaniem się z obiektem, ale to nie to samo i jest wiele sytuacji, w których chcesz mieć odpowiednią funkcję na prototypie zamiast właściwości.
W takich przypadkach użycie proxy lub
.bind()
faktycznie jest właściwym rozwiązaniem. (Chociaż cierpi na czytelność.)Więcej do czytania tutaj (nie głównie o TypeScript, ale zasady obowiązują):
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
źródło
Krótko mówiąc, słowo kluczowe this zawsze ma odniesienie do obiektu, który wywołał funkcję.
W JavaScript, ponieważ funkcje są tylko zmiennymi, możesz je przekazywać.
Przykład:
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
Gdy wykonasz następujące czynności z jQuery:
$.proxy(this.update, this);
To, co robisz, zastępuje ten kontekst. Za kulisami jQuery poprowadzi Cię w ten sposób:
$.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 } };
źródło
Co powiesz na zrobienie tego w ten sposób? Zadeklaruj zmienną globalną typu „myClass” i zainicjalizuj ją w konstruktorze klasy:
var _self: myClass; class myClass { classScopeVar: string = "hello"; constructor() { _self = this; } alerter() { setTimeout(function () { alert(_self.classScopeVar) }, 500); } } var classInstance = new myClass(); classInstance.alerter();
Uwaga: Ważne jest, aby NIE używać słowa „ja”, ponieważ jest to już specjalne znaczenie.
źródło