this

Introducci贸n

La palabra clave this de una funci贸n se comporta un poco diferente en Javascript en comparaci贸n con otros lenguajes. Adem谩s tiene algunas diferencias entre el modo estricto y el modo no estricto.

En general, el valor de this est谩 determinado por c贸mo se invoca a la funci贸n. No puede ser establecida mediante una asignaci贸n en tiempo de ejecuci贸n, y puede ser diferente cada vez que la funci贸n es invocada. ES5 introdujo el m茅todo bind() para establecer el valor de la funci贸n this independientemente de como es llamada, y ES2015 introdujo las funciones flecha que no proporcionan su propio "binding" de this (se mantiene el valor de this del contexto l茅xico que envuelve a la funci贸n)

Sintaxis

this

Valor

El objeto contexto de JavaScript en el cual se est谩 ejecutando el c贸digo actual.

Contexto global

En el contexto de ejecuci贸n global (fuera de cualquier funci贸n), this se refiere al objeto global, ya sea en modo estricto o no.

console.log(this.document === document); // true

// En los navegadores web, el objeto window tambi茅n es un objeto global:
console.log(this === window); // true

this.a = 37;
console.log(window.a); // 37

Nota: Puedes obtener el objeto global usando la propieda global globalThis, no importa el contexto donde se ejecute esta propiedad, siempre har谩 referencia al objeto global. 

Contexto de la funci贸n

Dentro de una funci贸n, el valor de this depende de c贸mo la funci贸n es llamada.

Llamada simple

function f1(){
  return this;
}

f1() === window; // objeto global
En este caso, el valor de this no est谩 establecido por la llamada. Dado que el c贸digo no est谩 en modo estricto, el valor de this debe ser siempre un objeto por lo que por defecto es el objeto global.
function f2(){
  "use strict"; // consultar modo estricto
  return this;
}

f2() === undefined;
En modo estricto, el valor de this se mantiene en lo que est谩 establecida al entrar en el contexto de ejecuci贸n. Si no est谩 definido, permanece undefined. Tambi茅n se puede ajustar a cualquier valor, tales como null o 42 o "Yo no soy this".

Nota: En el segundo ejemplo, this deber铆a ser undefined, porque f2 fue llamado sin proporcionar ninguna base (ej. window.f2()). Esta caracter铆stica no fue implementada en algunos navegadores cuando se comenz贸 a dar soporte al modo estricto. Como resultado, retorna incorrectamente el objeto window.

Como un m茅todo de un objeto

Cuando una funci贸n es llamada como un m茅todo de un objeto, el this cambia por el metodo del objeto llamado.

En el siguiente ejemplo, cuando o.f() es invocado, dentro de la funci贸n this es ligado al objeto o.

var o = {
  prop: 37,
  f: function() {
    return this.prop;
  }
};

console.log(o.f()); // logs 37

Note que el comportamiento no es del todo afectado por c贸mo o d贸nde la funci贸n fue definida. En el ejemplo anterior, nosotros definimos la funci贸n en l铆nea como el elemento f durante la definici贸n de o.  Sin embargo, podriamos haber definido con la misma facilidad la primera funci贸n y luego  adjuntarlo a o.f. Hacerlo da como resultado el mismo comportamiento.

var o = {prop: 37};

function independent() {
  return this.prop;
}

o.f = independent;

console.log(o.f()); // logs 37

Esto demuestra que s贸lo importa que la funci贸n fue invocada del elemento f de o.

Asimismo, el enlace this s贸lo se ve afectado por la referencia del miembro m谩s inmediata. En el siguiente ejemplo, cuando invocamos a la funci贸n, lo llamamos como metodo g del objeto o.b. Esta vez durante la ejecuci贸n, this dentro de la funci贸n se referir谩 a o.b. El hecho de que el objeto es en s铆 mismo un elemento de o no tiene ninguna consecuencia, la referencia m谩s inmediata es todo lo que importa.

o.b = {g: independent, prop: 42};
console.log(o.b.g()); // logs 42

... en la cadena de prototipo

El mismo concepto es v谩lido para los m茅todos definidos en alguna parte de la cadena de prototipo del objeto. Si el m茅todo esta sobre una cadena de prototipo del objeto, this se referir谩 al objeto donde est谩 el m茅todo de donde fue llamado. Como si ese m茅todo estuviera dentro del objeto. 

var o = {f:function(){ return this.a + this.b; }};
var p = Object.create(o);
p.a = 1;
p.b = 4;

console.log(p.f()); // 5

En este ejemplo, el objeto asignado a la variable p no tiene su propia propiedad f, esto lo hereda de su prototipo. Pero no importa que la b煤squeda de f eventualmente encuentre un elemento con ese nombre en o; la b煤squeda comenz贸 como una referencia a p.f, asi this dentro de la funcion toma el valor del objeto referido como p. Es decir, desde que f es llamado como m茅todo de p, su this refiere a p. Esto es una interesante caracter铆stica de la herencia de prototipo de JavaScript.

... o como un getter o setter

Nuevamente, el mismo concepto es v谩lido cuando una funci贸n es invocada de un getter o un setter. Una funci贸n usado como getter o setter tiene su enlace this al objeto desde el cual la propiedad esta siendo establecida u obtenida.

function modulus(){
  return Math.sqrt(this.re * this.re + this.im * this.im);
}

var o = {
  re: 1,
  im: -1,
  get phase(){
    return Math.atan2(this.im, this.re);
  }
};

Object.defineProperty(o, 'modulus', {get: modulus, enumerable:true, configurable:true});

console.log(o.phase, o.modulus); // logs -0.78 1.4142

Como un constructor

Cuando una funci贸n es usada como un constructor (con la palabra clave new), su this es enlazado al nuevo objeto en construcci贸n, a menos que la ejecuci贸n de los resultados del constructor en el motor JavaScript encuentren una instrucci贸n de retorno donde el valor de retorno sea un objeto.

/*
 * Los constructores trabajan algo asi:
 *
 * function MyConstructor(){
 *   // El cuerpo del c贸digo de la funci贸n actual va aqu铆.  Crear las propiedades en |this| como
 *   // se desee mediante la asignaci贸n a los mismos.  E.g.,
 *   this.fum = "nom";
 *   // etcetera...
 *
 *   // Si la funci贸n tiene una sentencia de retorno este retorna un objeto,
 *   // este objeto ser谩 el resultado de la expresi贸n |new|.  Por otro lado, el
 *   // resultado de la expresi贸n es el objeto actualmente enlazado a |this|
 *   // (i.e., el caso m谩s com煤n suele verse).
 * }
 */

function C(){
  this.a = 37;
}

var o = new C();
console.log(o.a); // logs 37


function C2(){
  this.a = 37;
  return {a:38};
}

o = new C2();
console.log(o.a); // logs 38

En el 煤ltimo ejemplo (C2), debido a que un objeto fue devuelto durante la construcci贸n, el nuevo objeto que fue enlazado a this simplemente se descarta.( Esto esencialmente hace de la declaraci贸n "this.a = 37;" codigo muerto. No esta exactamente muerto,porque es ejecutado pero se puede eliminar sin efectos externos.)

call y apply

Cuando una funci贸n usa la plabra clave this en su cuerpo, su valor puede ser enlazado a un objeto particular durante la ejecuci贸n del m茅todo call() or apply() que todas las funciones hereden de  Function.prototype.

function add(c, d){
  return this.a + this.b + c + d;
}

var o = {a:1, b:3};

// El primer par谩metro es el objeto a usar como 'this', par谩metros posteriores se pasan como argumentos
// en la llamada a la funci贸n
add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16

//El primer par谩metro es el objeto a usar como 'this''this', la segunda es una matriz cuyos elementos
//  se utilizan como argumentos en la llamada a la funci贸n
add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34

Funciones enlazadas

ECMAScript 5 introduce Function.prototype.bind(). Llamando a f.bind(someObject) crea una nueva funci贸n con el mismo cuerpo y alcance de f, pero donde this se produce en la funci贸n original, en la nueva funci贸n esto esta permanentemente ligado al primer argumento de bind, independientemente de c贸mo la funci贸n est谩 siendo utilizada.

function f(){
  return this.a;
}

var g = f.bind({a:"azerty"});
console.log(g()); // azerty

var o = {a:37, f:f, g:g};
console.log(o.f(), o.g()); // 37, azerty

Como un controlador de eventos DOM

Cuando una funci贸n es usada como un controlador de eventos, su this es cambiado desde el elemento del evento disparado (algunos navegadores no siguen esta convenci贸n para los listeners agregados din谩micamente con otros m茅todos addEventListener).

// Cuando se llama como un listener, convierte en azul el elemento
// relacionado
function bluify(e){
  console.log(this === e.currentTarget); // Siempre true
  console.log(this === e.target);        // true cuando currentTarget y target son el mismo objeto
  this.style.backgroundColor = '#A5D9F3';
}

// Consigue una lista de cada elemento en un documento
var elements = document.getElementsByTagName('*');

// A帽ade bluify como un click listener asi cuando se hace click sobre el elemento,
// este cambia a azul
for(var i=0 ; i<elements.length ; i++){
  elements[i].addEventListener('click', bluify, false);
}