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 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 son selfy that.
function MyConstructor(data, transport) {
this.data = data;
var self = this;
transport.on('data', function() {
alert(self.data);
});
}
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 al thisvalor de la devolución de llamada.
Conjunto explícito thisde la devolución de llamada - parte 1
Puede 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ón thisvinculada a un valor. La función tiene exactamente el mismo comportamiento que el que invocó .bind, solo que thisusted estableció. No importa cómo o cuándo se llame esa función, thissiempre 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 thisal 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 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.
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', () => alert(this.data));
}
Conjunto thisde la devolución de llamada - parte 2
Algunas 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:
array.map(callback[, thisArg])
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:
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, 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 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.methodse asigna como controlador de eventos de clic, pero si document.bodyse hace clic en él, el valor registrado será undefined, porque dentro del controlador de eventos, se thisrefiere a document.body, no a la instancia de Foo.
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:
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 .bindpara unirse explícitamente thisa 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();