En C++ y java tenemos bastante claro quien es this: un puntero estático a la instancia del objeto dueño del metodo que estemos implementado. En javascript no es tan claro, porque depende de donde se esté ejecutando la función y no de como o donde se declare esta. O sea this es el contexto.

javascript_logo

Veamos un ejemplo:

var me_llamo = function(){
return "yo me llamo:" + this.nombre;
};

me_llamo();
//=> "yo me llamo:undefined"

 

Está claro que no encontró una variable con nombre nombre (¿qué no se me podía ocurrir otro nombre?). Démosle una, ¿cómo?. Solo tenemos que añadir al contexto global una variable con este nombre, pues cuando llamas a una función de la forma que lo hicimos (nombre_funcion()) esta se ejecuta con this apuntando hacia allí.

this.nombre = "Global";
//esto mismo se puede hacer con
//nombre = "Global";
//porque las variables asignadas sin declarar son automáticamente globales.
me_llamo();
//=> "yo me  llamo:Global"

Ahora veamos otra forma de obtener el this.

var  persona = {nombre: 'Juán'};
persona.me_llamo = me_llamo;

persona.me_llamo();
//=> "yo me llamo: Juán"
persona['me_llamo']();
//=> "yo me llamo: Juán"
(persona)['me_llamo']();
//=> "yo me llamo: Juán"
(persona).me_llamo();
//=> "yo me llamo: Juán"
(persona.me_llamo)();
//=> "yo me llamo: Juán"

O sea, cuando llamas a la función como atributo de un objeto, este es el this para ella.

Otra forma de emplear una función es como constructora de objetos, con la palabra clave new. En este caso this es el objeto que la función está creando, así que no podemos usar nuestra función para estos menesteres, usemos esta otra para probar.

var Persona = function(nombre){
this.nombre = nombre;
};
var yo = new Persona('Leiser');
//=> Persona {nombre: "Leiser"}

Probemos añadir a la clase persona el método me_llamo.

Persona.prototype.me_llamo = me_llamo;
yo.me_llamo();
//=> "yo me llamo: Leiser"

En ocasiones es necesario fijar el this a una función, de modo que cada vez que se haga referencia a esta el valor apuntado sea el mismo, las implementaciones modernas proveen una forma de hacerlo, para ello usamos el atributo bind de las funciones.

Persona.prototype.me_llamo = me_llamo;
yo.me_llamo();
//=> "yo me llamo: Leiser"

Más adelante les enseñaré otra forma de hacerlo que funciona en implementaciones más viejas de javascript.

En otros momentos es necesario que la función tenga el this apuntando al this de donde se creó . Esto se puede resolver usando un idiom de javascript, conocido como that o self (me quedo con en segundo, me recuerda a python y ruby). Sería algo como esto:

var parent_name = (function(self) {
   return function() {
    console.log(self.nombre);
    };
  })(this);

Contextualizando

En javascript existen otras dos formas de llamar funciones, usando los atributos call y apply de estas. El primero ejecuta la función usando como parámetros de la misma el todos los que reciba a partir del segundo y como this, el que resiva de primero. Veamos un ejemplo:

una_funcion.call({"este":"es el this"}
                 arg1, arg2, arg3);

Su compañera, hace lo mismo pero solo recibe dos parámetros, el segundo será un arreglo con los argumentos.

una_funcion.apply({"este":"es el this"}
                 [arg1, arg2, arg3]);

Con esto y gracias a que toda función, guarda los argumentos con que es llamada en una variable especial llamada arguments, ya tenemos las herramientas para construir nuestro propio bind:

var bind = function(fn, me){
  return function(){
    return fn.apply(me, arguments);
  };
};

Lo que podríamos usar de la siguiente forma:

var mi_nombre = bind(yo.me_llamo, yo);
mi_nombre();
//=> "yo me llamo: Leiser"
yo.nombre = 'Alter Ego';
mi_nombre();
//=> "yo me llamo: Alter Ego"