En el art铆culo anterior聽 aprendimos qu茅 es (y qu茅 no es) this en JavaScript. Por si no te acuerdas:

this es una referencia que se crea cuando una funci贸n es invocada, no declarada. El valor de esa referencia depende al 100% del lugar en la que esa invocaci贸n se realice, llamado call-site.

Adem谩s, revisamos uno por uno los escenarios m谩s comunes donde el uso de this parece confuso si no eres consciente de cu谩les son las leyes que gobiernan su comportamiento.

De esta forma, vimos que en algunas circunstancias el valor de this cambia o, directamente, se pierde, examinando conceptos como default binding o implicit binding.

// Default binding
function miFuncion() {
    console.log(this);
}

miFuncion(); // global object o undefined en strict-mode

// Implicit binding
function miFuncion() {
    console.log(this.a);
}

var objeto = {
    a: 'Hola mundo'
    miFuncion: miFuncion,
};

objeto.miFuncion(); // Hola mundo

Explicit binding

Ahora bien, 驴existe alguna forma de forzar a una funci贸n a que, cuando sea invocada, use un valor espec铆fico de this?. La respuesta es si, todas las funciones en JavaScript tienen acceso a los m茅todos nativos apply y call, respectivamente.

Al invocar la funci贸n ambas toman como par谩metro el valor de this que deseamos, por eso se llama explicit binding. Aqu铆 tienes un ejemplo:

function saludar() {
    console.log('Hola, me llamo ' + this.nombre)
}

var persona =  {
    nombre: 'Juan',
}

var nombre = 'Andr茅s';

saludar(); // "Hola, me llamo Andr茅s"
saludar.call(persona); // "Hola, me llamo Juan"

Como puedes ver, con call invocamos la funci贸n saludar forzando el objeto persona como valor de this.

Por si te est谩s preguntando qu茅 diferencias hay entre call y apply: ninguna a efectos de this. Si que se comportan de forma diferente a la hora de recibir par谩metros.

A pesar de que con call o apply podemos de alguna forma forzar el valor de this en la invocaci贸n de la funci贸n, esto no resuelve por si s贸lo el problema que vimos anteriormente (perder la referencia a this). Considera esto:

function saludar() {
    console.log('Hola, me llamo ' + this.nombre)
}

var persona =  {
    nombre: 'Juan',
    saludar: saludar,
}

function ejecutar(funcion) {
    // "Aqu铆 perdemos la referencia a this, incluso con call"
    funcion(); 
}

var nombre = "Andr茅s";

ejecutar.call(persona, persona.saludar); // "Hola, me llamo Andr茅s"

La referencia se pierde ya que, como ya sabes, lo importante no es donde est谩 definida la funci贸n, sino desde d贸nde se invoca (call-site). En este caso es una simple funci贸n declarada, por lo que el default binding toma el control.

Hard binding

Existe una variante del binding expl铆cito que consigue unir de forma inalterable un contexto de this a la invocaci贸n de una funci贸n sin importar d贸nde se haga (call-site) esta:

function saludar() {
    console.log('Hola, me llamo ' + this.nombre);
}

var persona =  {
    nombre: 'Juan',
    saludar: saludar,
};

function unir() {
    saludar.call(persona);
}

var nombre = "Andr茅s";

unir(); // "Hola, me llamo Juan"

setTimeout(unir, 2000); // "Hola, me llamo Juan"

(function() {
    unir(); // "Hola, me llamo Juan"
})();

Como puedes comprobar, da igual desde qu茅 lugar invoquemos la funci贸n, el valor de this ha quedado fuertemente unido a la funci贸n, de ah铆 que lo llamemos Hard Binding.

El uso del hard binding es tan com煤n en JavaScript, que las funciones disponen de un m茅todo bind nativo. bind retorna una funci贸n lista para ser invocada y con su valor de this unido de forma indisoluble al contexto que indiquemos:

function saludar() {
    console.log('Hola, me llamo ' + this.nombre);
}

var persona =  {
    nombre: 'Juan',
};

var saludo = saludar.bind(persona);
saludo(); // "Hola, me llamo Juan"

Conclusi贸n

Durante dos art铆culos hemos examinado los escenarios m谩s comunes de invocaci贸n a funciones, revisando el valor de this en cada uno de ellos. Como ahora ya sabes, todo depende del lugar donde se realice esa invocaci贸n.

De esta forma, ya sea desde el 谩mbito global, a trav茅s de una llamada de construcci贸n, como m茅todo de un objeto o utilizando los m茅todos bind, call y/o apply, el valor de this no volver谩 鈥攅spero鈥 a sorprenderte.

Referencias