javascript - soljson - ¿Por qué ''esto'' no está definido dentro del método de clase cuando se usan promesas?
smart contracts ethereum (4)
Básicamente, le está pasando una referencia de función sin referencia de contexto.
this
contexto se determina de varias maneras:
- Implícitamente. Llamar a una función global o una función sin un enlace supone un contexto global. *
-
Por referencia directa.
Si llama a
myObj.f()
entoncesmyObj
será el contexto dethis
. ** -
Encuadernación manual.
Esta es su clase de funciones como
.bind
y.apply
. En estos se indica explícitamente cuál es el contexto. Estos siempre tienen prioridad sobre los dos anteriores.
En su ejemplo, está pasando una referencia de función, por lo que en su invocación se supone que es una función global o una sin contexto.
El uso de
.bind
resuelve esto creando una nueva función donde se establece explícitamente.
* Esto solo es cierto en modo no estricto.
En modo estricto,
this
está configurado como
undefined
.
** Suponiendo que la función que está utilizando no se ha vinculado manualmente.
Esta pregunta ya tiene una respuesta aquí:
- setTimeout y "this" en JavaScript 5 respuestas
Tengo una clase javascript y cada método devuelve una promesa
Q
Quiero saber por qué
this
no está definido en
method2
y
method3
.
¿Hay una forma más correcta de escribir este código?
function MyClass(opts){
this.options = opts;
return this.method1()
.then(this.method2)
.then(this.method3);
}
MyClass.prototype.method1 = function(){
// ...q stuff...
console.log(this.options); // logs "opts" object
return deferred.promise;
};
MyClass.prototype.method2 = function(method1resolve){
// ...q stuff...
console.log(this); // logs undefined
return deferred.promise;
};
MyClass.prototype.method3 = function(method2resolve){
// ...q stuff...
console.log(this); // logs undefined
return deferred.promise;
};
Puedo arreglar esto usando
bind
:
function MyClass(opts){
this.options = opts;
return this.method1()
.then(this.method2.bind(this))
.then(this.method3.bind(this));
}
Pero no del todo seguro por qué es necesario el
bind
;
¿Está
.then()
matando
this
?
Los manejadores de promesas se llaman en el contexto del objeto global (
window
) de forma predeterminada.
Cuando está en modo estricto (
use strict;
), el contexto
undefined
está
undefined
.
Esto es lo que le está sucediendo a
method2
y
method3
.
;(function(){
''use strict''
Promise.resolve(''foo'').then(function(){console.log(this)}); // undefined
}());
;(function(){
Promise.resolve(''foo'').then(function(){console.log(this)}); // window
}());
Para el
method1
, está llamando al
this.method1()
como
this.method1()
.
Esta forma de llamarlo lo llama en el contexto del objeto
this
que es su instancia.
Es por eso que el contexto dentro de
method1
es la instancia.
Una forma en que las funciones obtienen su contexto (
this
) es del objeto en el que se invocan (razón por la cual
method1
tiene el contexto correcto, se invoca en
this
).
Está pasando una referencia a la función en sí para
then
.
Puedes imaginar que la implementación de
then
ve así:
function then( callback ) {
// assume ''value'' is the recently-fulfilled promise value
callback(value);
}
En ese ejemplo, la
callback
es una referencia a su función.
No tiene ningún contexto.
Como ya ha notado, puede solucionarlo vinculando la función a un contexto antes de pasarla a ese momento.
this
es siempre el objeto al que se llama el método.
Sin embargo, al pasar el método a
then()
, ¡no lo está llamando!
El método se almacenará en algún lugar y se llamará desde allí más tarde.
Si desea preservar
this
, deberá hacerlo así:
.then(() => this.method2())
o si tiene que hacerlo de la forma anterior a ES6, debe preservar
this
antes de:
var that = this;
// ...
.then(function() { that.method2() })