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 datapropiedad del objeto creado dentro de la devolución de llamada. Parece que thisno 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
thisthis(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
thisNo usar
thisEn realidad, no desea acceder
thisen 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 sonselfythat.Como
selfes 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 althisvalor de la devolución de llamada.Conjunto explícito
thisde la devolución de llamada - parte 1Puede parecer que no tiene control sobre el valor de
thisporque 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ónthisvinculada a un valor. La función tiene exactamente el mismo comportamiento que el que invocó.bind, solo quethisusted estableció. No importa cómo o cuándo se llame esa función,thissiempre se referirá al valor pasado.En este caso, estamos vinculando las devoluciones de llamada
thisal 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
thisatadura. En cambio,thisse 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
thisde la devolución de llamada - parte 2Algunas funciones / métodos que aceptan devoluciones de llamada también aceptan un valor al que
thisdeberí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
thisdebe referirse. Aquí hay un ejemplo artificial:Nota: Si puede pasar un valor o no,
thisgeneralmente se menciona en la documentación de esa función / método. Por ejemplo, el$.ajaxmé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.methodse asigna como controlador de eventos de clic, pero sidocument.bodyse hace clic en él, el valor registrado seráundefined, porque dentro del controlador de eventos, sethisrefiere adocument.body, no a la instancia deFoo.Como ya se mencionó al principio, lo que se
thisrefiere 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
.bindpara unirse explícitamentethisa 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
selfythatpara referirsethis. Me siento así porquethises una variable sobrecargada utilizada en diferentes contextos; mientras queselfgeneralmente corresponde a la instancia local ythatgeneralmente 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
$.proxymétodo, yabindque 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
thispero 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
scopey un comportamiento claros de lasthispalabras 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.
thisLa palabra clave en el ámbito global se refiere al objeto de ventana.thisla función interna también se refiere al objeto de la ventana, porthislo que siempre se referirá a la ventana hasta que encontremos una forma de manipularthispara indicar un contexto de nuestra propia elección.Diferentes formas de manipular las
thisfunciones de devolución de llamada:Aquí tengo una función constructora llamada Persona. Tiene una propiedad llamada
namey 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
sayNameVersionXmétodo (X se refiere a 1,2,3,4)niceCallbackpara ver cuántas formas podemos manipular lathisdevolución de llamada interna para referirnos a lapersoninstancia.enlace:
Lo que hace bind es crear una nueva función con la
thispalabra clave establecida en el valor proporcionado.sayNameVersion1ysayNameVersion2use bind para manipularthisla función de devolución de llamada.el primero se vincula
thiscon 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 argumentdelcallmétodo se utiliza comothisdentro de la función que se invoca concallunido a él.sayNameVersion3utilizacallpara manipular elthispara 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 seapplyrefiere al objeto que será indicado porthispalabra clave.sayNameVersion4utilizaapplypara manipularthispara 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 althiscontexto 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
thiscomporta la palabra clave en javascript.thisse comporta de manera diferente como a continuación,thisgeneralmente está determinado por un contexto de ejecución de funciones.thisrefiere al objeto global (elwindowobjeto).thisseráundefinedcomo en el modo estricto, el objeto global se refiereundefineden lugar delwindowobjeto.call(),bind()yapply()newse usa palabra clave (un constructor), está vinculada al nuevo objeto que se está creando.this; en cambio,thisse 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 = thisEntonces, la mejor solución sería usar lambdas como se muestra a continuación,
Referencias
fuente
thispalabra clave, por eso dividí mi respuesta en dos partes, una sobrethisy 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
thisdentro del detector de eventos, que le permite eliminar siempre el receptor (entre otros beneficios), es elhandleEvent(evt)método de laEventListenerinterfaz:Puede encontrar información detallada sobre el uso
handleEventaquí: https://medium.com/@WebReflection/dom-handleevent-a-cross-platform-standard-since-year-2000-5bf17287fd38fuente
thisen JS:El valor de
thisen 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 dethisla 'izquierda de la regla de puntos' :thises el objeto a la izquierda del punto de la función que se llamathisdentro de una función es a menudo el objeto global (globalen el nodo,windowen el navegador). No recomendaría usar lathispalabra 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):
thisesobj2por la izquierda de la regla de puntos, podemos ver cómotest1se llamaobj2.test1();.obj2queda del punto y por lo tanto elthisvalor.obj2que queda del punto,test2está obligado aobj1través delbind()método. Entonces elthisvalor esobj1.obj2que queda del punto de la función que se llama:obj2.test3(). Porobj2lo tanto será el valor dethis.obj2.test4()obj2queda del punto. Sin embargo, la función de flecha no tiene su propiothisenlace. Por lo tanto, se unirá althisvalor del ámbito externo, que es elmodule.exportsobjeto que se registró al principio.thismediante el uso de lacallfunción. Aquí podemos pasar elthisvalor deseado como argumento, que esobj2en este caso.fuente