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:
function foo() {
console.log(this);
}
// normal function call
foo(); // `this` will refer to `window`
// as object method
var obj = {bar: foo};
obj.bar(); // `this` will refer to `obj`
// as constructor function
new foo(); // `this` will refer to an object that inherits from `foo.prototype`
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 son self
y that
.
function MyConstructor(data, transport) {
this.data = data;
var self = this;
transport.on('data', function() {
alert(self.data);
});
}
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 al this
valor de la devolución de llamada.
Conjunto explícito this
de la devolución de llamada - parte 1
Puede 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ón this
vinculada a un valor. La función tiene exactamente el mismo comportamiento que el que invocó .bind
, solo que this
usted estableció. No importa cómo o cuándo se llame esa función, this
siempre se referirá al valor pasado.
function MyConstructor(data, transport) {
this.data = data;
var boundFunction = (function() { // parenthesis are not necessary
alert(this.data); // but might improve readability
}).bind(this); // <- here we are calling `.bind()`
transport.on('data', boundFunction);
}
En este caso, estamos vinculando las devoluciones de llamada this
al valor de MyConstructor
's this
.
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 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.
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', () => alert(this.data));
}
Conjunto this
de la devolución de llamada - parte 2
Algunas 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:
array.map(callback[, thisArg])
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:
var arr = [1, 2, 3];
var obj = {multiplier: 42};
var new_arr = arr.map(function(v) {
return v * this.multiplier;
}, obj); // <- here we are passing `obj` as second argument
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 llamada context
:
Este objeto se convertirá en el contexto de todas las devoluciones de llamada relacionadas con Ajax.
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:
function Foo() {
this.data = 42,
document.body.onclick = this.method;
}
Foo.prototype.method = function() {
console.log(this.data);
};
La función this.method
se asigna como controlador de eventos de clic, pero si document.body
se hace clic en él, el valor registrado será undefined
, porque dentro del controlador de eventos, se this
refiere a document.body
, no a la instancia de Foo
.
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:
function method() {
console.log(this.data);
}
function Foo() {
this.data = 42,
document.body.onclick = this.method;
}
Foo.prototype.method = method;
La solución es la misma que se mencionó anteriormente: si está disponible, úsela .bind
para unirse explícitamente this
a un valor específico
document.body.onclick = this.method.bind(this);
o 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:
var self = this;
document.body.onclick = function() {
self.method();
};
o use una función de flecha:
document.body.onclick = () => this.method();