Tengo una función de constructor que registra un controlador de eventos:
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', function () {
alert(this.data);
});
}
// Mock transport object
var transport = {
on: function(event, callback) {
setTimeout(callback, 1000);
}
};
// called as
var obj = new MyConstructor('foo', transport);
Sin embargo, no puedo acceder a la data
propiedad del objeto creado dentro de la devolución de llamada. Parece que this
no se refiere al objeto que se creó, sino a otro.
También intenté usar un método de objeto en lugar de una función anónima:
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', this.alert);
}
MyConstructor.prototype.alert = function() {
alert(this.name);
};
pero exhibe los mismos problemas.
¿Cómo puedo acceder al objeto correcto?
javascript
callback
this
Felix Kling
fuente
fuente
Respuestas:
Lo que debes saber sobre
this
this
(también conocido como "el contexto") es una palabra clave especial dentro de cada función y su valor solo depende de cómo se llamó a la función, no de cómo / cuándo / dónde se definió. No se ve afectado por ámbitos léxicos como otras variables (a excepción de las funciones de flecha, ver más abajo). Aquí hay unos ejemplos:Para obtener más información
this
, consulte la documentación de MDN .Cómo referirse a la correcta
this
No usar
this
En realidad, no desea acceder
this
en particular, pero el objeto al que hace referencia . Es por eso que una solución fácil es simplemente crear una nueva variable que también se refiera a ese objeto. La variable puede tener cualquier nombre, pero los comunes sonself
ythat
.Como
self
es una variable normal, obedece las reglas de alcance léxico y es accesible dentro de la devolución de llamada. Esto también tiene la ventaja de que puede acceder althis
valor de la devolución de llamada.Conjunto explícito
this
de la devolución de llamada - parte 1Puede parecer que no tiene control sobre el valor de
this
porque su valor se establece automáticamente, pero ese no es el caso.Cada función tiene el método
.bind
[docs] , que devuelve una nueva funciónthis
vinculada a un valor. La función tiene exactamente el mismo comportamiento que el que invocó.bind
, solo quethis
usted estableció. No importa cómo o cuándo se llame esa función,this
siempre se referirá al valor pasado.En este caso, estamos vinculando las devoluciones de llamada
this
al valor deMyConstructor
'sthis
.Nota: Al vincular el contexto para jQuery, use
jQuery.proxy
[docs] en su lugar. La razón para hacer esto es para que no necesite almacenar la referencia a la función al desvincular una devolución de llamada de evento. jQuery maneja eso internamente.ECMAScript 6: Usar funciones de flecha
ECMAScript 6 introduce funciones de flecha , que pueden considerarse funciones lambda. No tienen su propia
this
atadura. En cambio,this
se busca en el alcance al igual que una variable normal. Eso significa que no tienes que llamar.bind
. Ese no es el único comportamiento especial que tienen, consulte la documentación de MDN para obtener más información.Conjunto
this
de la devolución de llamada - parte 2Algunas funciones / métodos que aceptan devoluciones de llamada también aceptan un valor al que
this
deberían referirse las devoluciones de llamada . Esto es básicamente lo mismo que vincularlo usted mismo, pero la función / método lo hace por usted.Array#map
[docs] es un método de este tipo. Su firma es:El primer argumento es la devolución de llamada y el segundo argumento es el valor al que
this
debe referirse. Aquí hay un ejemplo artificial:Nota: Si puede pasar un valor o no,
this
generalmente se menciona en la documentación de esa función / método. Por ejemplo, el$.ajax
método [docs] de jQuery describe una opción llamadacontext
:Problema común: uso de métodos de objeto como devoluciones de llamada / controladores de eventos
Otra manifestación común de este problema es cuando se usa un método de objeto como devolución de llamada / controlador de eventos. Las funciones son ciudadanos de primera clase en JavaScript y el término "método" es solo un término coloquial para una función que es un valor de una propiedad de objeto. Pero esa función no tiene un enlace específico a su objeto "que contiene".
Considere el siguiente ejemplo:
La función
this.method
se asigna como controlador de eventos de clic, pero sidocument.body
se hace clic en él, el valor registrado seráundefined
, porque dentro del controlador de eventos, sethis
refiere adocument.body
, no a la instancia deFoo
.Como ya se mencionó al principio, lo que se
this
refiere depende de cómo se llama la función , no de cómo se define .Si el código fuera el siguiente, podría ser más obvio que la función no tiene una referencia implícita al objeto:
La solución es la misma que se mencionó anteriormente: si está disponible, úsela
.bind
para unirse explícitamentethis
a un valor específicoo llame explícitamente a la función como un "método" del objeto, utilizando una función anónima como devolución de llamada / controlador de eventos y asigne el objeto (
this
) a otra variable:o use una función de flecha:
fuente
self
ythat
para referirsethis
. Me siento así porquethis
es una variable sobrecargada utilizada en diferentes contextos; mientras queself
generalmente corresponde a la instancia local ythat
generalmente se refiere a otro objeto. Sé que no estableció esta regla, como la he visto aparecer en varios otros lugares, pero también es por eso que comencé a usarla_this
, pero no estoy seguro de cómo se sienten los demás, excepto por la práctica no uniforme eso ha resultado.Function.prototype.call ()
yFunction.prototype.apply ()
. Particularmente conapply ()
he conseguido mucho kilometraje. Estoy menos inclinado a usarbind ()
tal vez solo por costumbre, aunque soy consciente (pero no estoy seguro) de que puede haber ligeras ventajas generales al usar el enlace sobre las otras opciones.() => this.clicked()
;)Aquí hay varias formas de acceder al contexto primario dentro del contexto secundario:
bind()
función.1. Uso
bind()
funciónSi está utilizando
underscore.js
: http://underscorejs.org/#bind2 Almacene la referencia al contexto / esto dentro de otra variable
3 función de flecha
fuente
Todo está en la sintaxis "mágica" de llamar a un método:
Cuando obtiene la propiedad del objeto y la llama de una vez, el objeto será el contexto del método. Si llama al mismo método, pero en pasos separados, el contexto es el alcance global (ventana) en su lugar:
Cuando obtienes la referencia de un método, ya no está adjunto al objeto, es solo una referencia a una función simple. Lo mismo sucede cuando obtienes la referencia para usar como devolución de llamada:
Ahí es donde vincularía el contexto a la función:
Si está utilizando jQuery, debe utilizar el
$.proxy
método, yabind
que no es compatible con todos los navegadores:fuente
El problema con el "contexto"
El término "contexto" se utiliza a veces para referirse al objeto referenciado por este . Su uso es inapropiado porque no encaja semántica o técnicamente con ECMAScript's this .
"Contexto" significa las circunstancias que rodean algo que agrega significado, o alguna información anterior y siguiente que le da un significado adicional. El término "contexto" se usa en ECMAScript para referirse al contexto de ejecución , que es todos los parámetros, alcance y esto dentro del alcance de algún código de ejecución.
Esto se muestra en la sección 10.4.2 de ECMA-262 :
lo que indica claramente que esto es parte de un contexto de ejecución.
Un contexto de ejecución proporciona la información circundante que agrega significado al código que se está ejecutando. Incluye mucha más información que solo thisBinding .
Entonces el valor de esto no es "contexto", es solo una parte de un contexto de ejecución. Es esencialmente una variable local que puede establecerse mediante la llamada a cualquier objeto y, en modo estricto, a cualquier valor.
fuente
this
pero aquí no se ofrece ninguno, y podría decirse que es demasiado tarde para cerrar la puerta al "contexto".Debe saber sobre "esta" palabra clave.
Según mi punto de vista, puede implementar "esto" de tres maneras (Self / Función de flecha / Método de enlace)
Una función de esta palabra clave se comporta de manera un poco diferente en JavaScript en comparación con otros idiomas.
También tiene algunas diferencias entre el modo estricto y el modo no estricto.
En la mayoría de los casos, el valor de esto está determinado por cómo se llama una función.
No se puede establecer mediante asignación durante la ejecución, y puede ser diferente cada vez que se llama a la función.
ES5 introdujo el método bind () para establecer el valor de una función, independientemente de cómo se llame,
y ES2015 introdujo funciones de flecha que no proporcionan su propia vinculación (conserva el valor de este contexto léxico adjunto).
Método 1: Self - Self se está utilizando para mantener una referencia al original, incluso cuando el contexto está cambiando. Es una técnica de uso frecuente en los controladores de eventos (especialmente en cierres).
Referencia : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
Método 2 : Función de flecha: una expresión de función de flecha es una alternativa sintácticamente compacta a una expresión de función regular,
aunque sin sus propios enlaces a las palabras clave this, argumentos, super o new.target.
Las expresiones de función de flecha no son adecuadas como métodos, y no pueden usarse como constructores.
Referencia : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
Método 3 : : el método bind () crea una nueva función que,
cuando se le llama, tiene esta palabra clave establecida en el valor proporcionado,
con una secuencia dada de argumentos que preceden a cualquier proporcionado cuando se llama a la nueva función.
Referencia: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind
fuente
Primero, debe tener una comprensión
scope
y un comportamiento claros de lasthis
palabras clave en el contexto descope
.this
&scope
:en resumen, el alcance global se refiere al objeto de ventana. Las variables declaradas en un alcance global son accesibles desde cualquier lugar. Por otro lado, el alcance de la función reside dentro de una función. Normalmente no se puede acceder a la variable declarada dentro de una función desde el mundo exterior.
this
La palabra clave en el ámbito global se refiere al objeto de ventana.this
la función interna también se refiere al objeto de la ventana, porthis
lo que siempre se referirá a la ventana hasta que encontremos una forma de manipularthis
para indicar un contexto de nuestra propia elección.Diferentes formas de manipular las
this
funciones de devolución de llamada:Aquí tengo una función constructora llamada Persona. Tiene una propiedad llamada
name
y cuatro método llamadosayNameVersion1
,sayNameVersion2
,sayNameVersion3
,sayNameVersion4
. Los cuatro tienen una tarea específica. Aceptar una devolución de llamada e invocarla. La devolución de llamada tiene una tarea específica que es registrar la propiedad de nombre de una instancia de la función de constructor de Persona.Ahora creemos una instancia del constructor de personas e invoquemos diferentes versiones del
sayNameVersionX
método (X se refiere a 1,2,3,4)niceCallback
para ver cuántas formas podemos manipular lathis
devolución de llamada interna para referirnos a laperson
instancia.enlace:
Lo que hace bind es crear una nueva función con la
this
palabra clave establecida en el valor proporcionado.sayNameVersion1
ysayNameVersion2
use bind para manipularthis
la función de devolución de llamada.el primero se vincula
this
con la devolución de llamada dentro del propio método. Y para el segundo, la devolución de llamada se pasa con el objeto vinculado a él.llamada :
El
first argument
delcall
método se utiliza comothis
dentro de la función que se invoca concall
unido a él.sayNameVersion3
utilizacall
para manipular elthis
para referirse al objeto de persona que creamos, en lugar del objeto de ventana.y se llama así:
aplicar :
Similar a
call
, el primer argumento de seapply
refiere al objeto que será indicado porthis
palabra clave.sayNameVersion4
utilizaapply
para manipularthis
para referirse al objeto personay se llama de la siguiente manera. Simplemente se pasa la devolución de llamada,
fuente
No podemos vincular esto a
setTimeout()
, ya que siempre se ejecuta con el objeto global (Ventana) , si desea acceder althis
contexto en la función de devolución de llamada, utilizandobind()
la función de devolución de llamada podemos lograr lo siguiente:fuente
La pregunta gira en torno a cómo se
this
comporta la palabra clave en javascript.this
se comporta de manera diferente como a continuación,this
generalmente está determinado por un contexto de ejecución de funciones.this
refiere al objeto global (elwindow
objeto).this
seráundefined
como en el modo estricto, el objeto global se refiereundefined
en lugar delwindow
objeto.call()
,bind()
yapply()
new
se usa palabra clave (un constructor), está vinculada al nuevo objeto que se está creando.this
; en cambio,this
se vincula léxicamente (es decir, según el contexto original)Como la mayoría de las respuestas sugieren, podemos usar la función de flecha o
bind()
Método o Self var. Citaría un punto sobre lambdas (función de flecha) de la Guía de estilo de JavaScript de GoogleGoogle recomienda claramente usar lambdas en lugar de enlazar o
const self = this
Entonces, la mejor solución sería usar lambdas como se muestra a continuación,
Referencias
fuente
this
palabra clave, por eso dividí mi respuesta en dos partes, una sobrethis
y la segunda sobre el uso de funciones / métodos como devoluciones de llamada. Siéntase libre de editar la respuesta.Actualmente hay otro enfoque posible si se usan clases en el código.
Con soporte de campos de clase , es posible hacerlo de la siguiente manera:
Seguramente, bajo el capó, todo es una buena función de flecha buena que vincula el contexto, pero de esta forma se ve mucho más claro que el enlace explícito.
Dado que es la Propuesta de la Etapa 3, necesitará babel y el complemento de babel apropiado para procesarlo por ahora (08/2018).
fuente
public methodName = (params) => { body }
dentro de una clase.Otro enfoque, que es la forma estándar desde que DOM2 se une
this
dentro del detector de eventos, que le permite eliminar siempre el receptor (entre otros beneficios), es elhandleEvent(evt)
método de laEventListener
interfaz:Puede encontrar información detallada sobre el uso
handleEvent
aquí: https://medium.com/@WebReflection/dom-handleevent-a-cross-platform-standard-since-year-2000-5bf17287fd38fuente
this
en JS:El valor de
this
en JS está 100% determinado por cómo se llama una función y no por cómo se define. Podemos relativamente fácil encontrar el valor dethis
la 'izquierda de la regla de puntos' :this
es el objeto a la izquierda del punto de la función que se llamathis
dentro de una función es a menudo el objeto global (global
en el nodo,window
en el navegador). No recomendaría usar lathis
palabra clave aquí porque es menos explícita que usar algo comowindow
!Function.prototype.bind()
función que puede fijar el valor dethis
. Estas son excepciones de la regla, pero son realmente útiles para fijar el valor dethis
.Ejemplo en nodeJS
Salida:
Déjame guiarte a través de las salidas 1 por 1 (ignorando el primer registro a partir del segundo):
this
esobj2
por la izquierda de la regla de puntos, podemos ver cómotest1
se llamaobj2.test1();
.obj2
queda del punto y por lo tanto elthis
valor.obj2
que queda del punto,test2
está obligado aobj1
través delbind()
método. Entonces elthis
valor esobj1
.obj2
que queda del punto de la función que se llama:obj2.test3()
. Porobj2
lo tanto será el valor dethis
.obj2.test4()
obj2
queda del punto. Sin embargo, la función de flecha no tiene su propiothis
enlace. Por lo tanto, se unirá althis
valor del ámbito externo, que es elmodule.exports
objeto que se registró al principio.this
mediante el uso de lacall
función. Aquí podemos pasar elthis
valor deseado como argumento, que esobj2
en este caso.fuente