Sé que esto probablemente sea dolorosamente básico, pero me está costando entenderlo.
class Main
{
constructor()
{
requestAnimationFrame(this.update); //fine
}
update(): void
{
requestAnimationFrame(this.update); //error, because this is window
}
}
Parece ser el caso de que necesito un proxy, así que digamos usando Jquery
class Main
{
constructor()
{
this.updateProxy = $.proxy(this.update, this);
requestAnimationFrame(this.updateProxy); //fine
}
updateProxy: () => void
update(): void
{
requestAnimationFrame(this.updateProxy); //fine
}
}
Pero teniendo en cuenta los antecedentes de Actionscript 3, no estoy seguro de lo que está sucediendo aquí. Lo siento, no estoy seguro de dónde comienza Javascript y termina TypeScript.
updateProxy: () => void
Además, no estoy convencido de que esté haciendo esto bien. Lo último que quiero es que la mayor parte de mi clase tenga una función aa () a la que se debe acceder, aProxy()
ya que siento que estoy escribiendo lo mismo dos veces. ¿Es normal?
jquery
this
typescript
proxy-classes
Clark
fuente
fuente
Respuestas:
Si desea
this
capturar, la forma de TypeScript de hacerlo es a través de las funciones de flecha. Para citar a Anders:Esta es la forma en que me gusta usar esto para mi ventaja:
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; }
Ver esto en TypeScript Playground
Puede ver que en el JavaScript generado
this
se captura fuera de la llamada a la función:var _this = this; this.prop = 10; this.func1 = function (arg) { return arg + " yeah" + _this.prop; };
por lo que el
this
valor dentro de la llamada a la función (que podría serwindow
) no se usaría.Para obtener más información: "Comprensión
this
de TypeScript" (4:05) - YouTubefuente
var _this = this;
debes elegirES5
; desde ES2015 - funciones internas -this
se usa en lugar de_this
Si escribe sus métodos de esta manera, "esto" se tratará de la manera que espera.
class Main { constructor() { requestAnimationFrame(() => this.update()); } update(): void { requestAnimationFrame(() => this.update()); } }
Otra opción sería vincular 'esto' a la llamada a la función:
class Main { constructor() { requestAnimationFrame(this.update.bind(this)); } update(): void { requestAnimationFrame(this.update.bind(this)); } }
fuente
Consulte la página 72 de la especificación del lenguaje mecanografiado https://github.com/Microsoft/TypeScript/blob/master/doc/TypeScript%20Language%20Specification.pdf?raw=true
Expresiones de función de flecha
En el ejemplo
class Messenger { message = "Hello World"; start() { setTimeout(() => alert(this.message), 3000); } }; var messenger = new Messenger(); messenger.start();
Este es el Javascript generado real:
class Messenger { message = "Hello World"; start() { var _this = this; setTimeout(function() { alert(_this.message); }, 3000); } };
fuente
El problema surge cuando pasa una función como devolución de llamada. Para cuando la devolución de llamada se haya ejecutado, el valor de "this" podría haber cambiado a la ventana, el control que invoca la devolución de llamada o algo más.
Asegúrese de usar siempre una expresión lambda en el punto en que pasa una referencia a la función que se llamará de nuevo. Por ejemplo
public addFile(file) { this.files.push(file); } //Not like this someObject.doSomething(addFile); //but instead, like this someObject.doSomething( (file) => addFile(file) );
Esto se compila en algo como
this.addFile(file) { this.files.push(file); } var _this = this; someObject.doSomething(_this.addFile);
Debido a que se llama a la función addFile en una referencia de objeto específica (_this), no usa el "this" del invocador sino el valor de _this.
fuente
En resumen, la palabra clave this siempre tiene una referencia al objeto que llamó a la función.
En Javascript, dado que las funciones son solo variables, puede pasarlas.
Ejemplo:
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
Cuando haces lo siguiente con jQuery:
$.proxy(this.update, this);
Lo que está haciendo es anular ese contexto. Detrás de escena, jQuery te guiará esto:
$.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 } };
fuente
Muy tarde para la fiesta, pero creo que es muy importante que los futuros visitantes de esta pregunta consideren lo siguiente:
Las otras respuestas, incluida la aceptada, pierden un punto crucial:
y
myFunction = () => { ... }
no son lo mismo "con la salvedad de que este último captura
this
".La primera sintaxis crea un método en el prototipo, mientras que la segunda sintaxis crea una propiedad en el objeto cuyo valor es una función (que también pasa a capturar
this
). Puede ver esto claramente en el JavaScript transpilado.Estar Completo:
myFunction = function() { ... }
sería la misma que la segunda sintaxis, pero sin la captura.
Entonces, usar la sintaxis de flecha en la mayoría de los casos solucionará su problema de vinculación al objeto, pero no es lo mismo y hay muchas situaciones en las que desea tener una función adecuada en el prototipo en lugar de una propiedad.
En estos casos utilizar un proxy o en
.bind()
realidad es la solución correcta. (Aunque sufre legibilidad).Más lectura aquí (no principalmente sobre TypeScript, pero los principios se mantienen):
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
fuente
¿Qué tal hacerlo de esta manera? Declare una variable global de tipo "myClass" e inicialícela en el constructor de la clase:
var _self: myClass; class myClass { classScopeVar: string = "hello"; constructor() { _self = this; } alerter() { setTimeout(function () { alert(_self.classScopeVar) }, 500); } } var classInstance = new myClass(); classInstance.alerter();
Nota: Es importante NO usar "self", ya que ya tiene un significado especial.
fuente