Introducción
this es un valor complejo en Javascript; un error en el diseño del lenguaje susceptible de causar tanto comportamientos inesperados como potentes estructuras de código reutilizable. Su valor, lejos de ser intuitivo, se determina según la forma en que se invoque a la función que lo encierra, algo que no siempre es correctamente entendido o aprovechado.
Dado que el correcto manejo de this resulta esencial en la programación orientada a objetos, y en definitiva en el desarrollo moderno de aplicaciones, es interesante dedicar unos minutos a revisarlo.
Qué es exactamente this
La palabra clave this tiene en Javascript un comportamiento diferente al de otros lenguajes pero por lo general, su valor hace referencia al propietario de la función que la está invocando o en su defecto, al objeto donde dicha función es un método.
La palabra clave del párrafo anterior es “propietario“.
Cuando no estamos dentro de una estructura definida, esto es un objeto con métodos, el propietario de una función es siempre el contexto global. En el caso de los navegadores web, tenemos que recordar que dicho objeto es window:
console.log( this === window ); // true function test(){ console.log( this === window); } test(); // true |
Accediendo a los valores de un objeto desde el propio objeto
Este concepto de propietario puede inducir a errores. Pensemos en un objeto con una serie de propiedades:
var myApp = { name : 'Megan', lastName : 'Fox', birthDate : '16/05/1986', isPretty : true }; console.log( myApp.name ); // Megan console.log( myApp.isPretty ); // true |
Supongamos ahora que necesitamos otra propiedad más ‘dinámica’ que participe de los valores asignados a cualquier otra. Por ejemplo, queremos un ‘completeName‘ que concatene ‘name‘ y ‘lastName‘. Parece que este un claro ejemplo de uso para this:
var myApp = { name : 'Megan', lastName : 'Fox', completeName : this.name + this.lastName } |
Aunque parece coherente, cuando pasamos a comprobarlo vemos que el resultado no es el esperado:
console.log( myApp.completeName ); // undefined |
El problema aquà es que this no está apuntando al objeto como cabrÃa esperar, sino que está buscando la referencia fuera, en el contexto global (window).
Para obtener el resultado esperado tenemos que aplicar un patrón de invocación que modifique al propietario desde el que se invoca el this…
Patrón de invocación por método
En Javascript, existen varias formas de llamar a las funciones desde nuestro código; concretamente, podemos enumerar hasta cinco diferentes. La elección de una u otra responde al flujo de nuestro programa pero básicamente, difieren en el contexto que queramos aplicar a cada una. O lo que es lo mismo, al valor que queramos que la función asigne a la referencia this.
En el desarrollo de aplicaciones modernas, el patrón más recurrente es el de invocación por método: una función es almacenada como propiedad de un objeto convirtiéndose asà en lo que denominamos un método.
Cuando llamamos (invocamos) a un método, this hace refencia al propio objeto:
var myApp = { name : 'Megan', lastName : 'Fox', completeName : function(){ return this.name + ' ' + this.lastName; } } console.log( myApp.completeName() ); // Megan Fox |
En esta ocasión, si podemos comprobar como this apunta al propio objeto y busca la propiedades ‘name‘ y ‘lastName‘ dentro en lugar de remontarse hasta el contexto global.
Pero como vimos en el caso anterior, no siempre el uso de this es intuitivo. Consideremos la siguiente estructura:
var myApp = function(){ var name = "World" var sayHello = function(){ console.log( 'Hello, ' + this.name ); }; sayHello(); // Invoke the function }; myApp(); // Hello, |
¿A dónde está apuntando this en este caso? Como la función no es ahora la propiedad de un objeto, this apunta de nuevo al global (window). Esto es un error en el diseño del lenguaje ya que, de comportarse como se espera, this deberÃa apuntar a la función contenedora (que no deja de ser su propietaria).
Este comportamiento lo podemos comprobar si creamos una variable global con aquel nombre por el que estamos preguntando:
var name = "Strange World"; var myApp = function(){ var name = "World" var sayHello = function(){ console.log( 'Hello, ' + this.name ); }; sayHello(); }; myApp(); // Hello, Strange World |
La consecuencia de este error es que un método no puede utilizar funciones internas que la ayuden a hacer su trabajo porque éstas, no tiene acceso a sus propiedades.
Para resolver este problema, podemos recurrir a una solución muy simple: definir dentro de nuestra función contenedora una nueva variable que cachee el valor de this para que asà esté disponible desde cualquier otra función anidada que lo precise. Por convención, el nombre de esta variable es that:
var myApp = function(){ var that = this; // Work around! var name = "World" var sayHello = function(){ console.log( 'Hello, ' + that.name ); }; sayHello(); }; myApp(); // Hello, World |
NOTA: Últimamente, la convención que propuso Douglas Crockford está siendo revisada y son muchos los desarrolladores que prefieren el término self para referirse al objeto cacheado.
Sobreescribiendo el valor de this en tiempo de ejecución
Una de las caracterÃsticas consideradas avanzadas dentro del lenguaje Javascript es la posibilidad de reescribir el valor de this en tiempo de ejecución consiguiendo asà una modularidad y reusabilidad extrema.
Más arriba comentamos que existen varias formas de invocar funciones en Javascript donde la elección entre una u otra depende del valor que queramos asignar a this.
Consideremos el siguiente codigo:
var person1 = { name : 'Angelina', lastName : 'Jolie', birthDay : '04/06/1975', lastMovie : 'The Tourist' }; var person2 = { name : 'Scarlett', lastName : 'Johansson', birthDay : '22/11/1984', lastMovie : 'We bought a Zoo' } var printName = function(){ console.log( this.name + ' ' + this.lastName ); } |
Si tratamos de ejecutar sin más la función printName, ya sabemos que el this apunta al objeto global window e irá ahà a buscar las propiedas name y lastName.
En una arquitectura modular, lo ideal es que esa función pueda ser reaprovechada y que nos permita imprimir los datos de cualquier objeto que cumpla con los requisitos. Para ello, podemos cambiar el valor de this en tiempo de ejecución con el fin de que apunte a ese objeto en cuestión. Para ello, contamos con las funciones nativas apply y call:
printName.call( person1 ); // Angelina Jolie printName.call( person2 ); // Scarlett Johansson printName.apply( person1 ); // Angelina Jolie printName.apply( person2 ); // Scarlett Johansson |
El resultado es el mismo: hemos ejecutado la función printName dentro del contexto de cada uno de los objetos que hemos pasado como argumento.
La diferencia entre cada uno de estas funciones es que la segunda de ellas, apply, acepta un array como argumento, lo que permite una flexibilidad aún mayor a la hora de plantear código reusable.
Pensemos en una función que nos permita actualizar datos dentro de nuestros objetos:
var updatePerson = function(name, lastName, birthDay, lastMovie){ this.name = name; this.lastName = lastName; this.birthDay = birthDay; this.lastMovie = lastMovie; } updatePerson( person1, 'Angelina', 'Jolie', '04/06/1975', 'Kung Fu Panda 2'); |
Las limitaciones de call se hacen rápidamente evidentes cuando queremos escribir código que no conoce (o no debe conocer) el número de argumentos que la función necesita.
Tomemos por ejemplo una función que siga el conocido paradigma del ‘dispatcher‘:
var dispatch = function(person, method, args){ method.apply( person, args ); } dispatch( person1, printName ); dispatch( person2, update, ['Scarlett', 'Johansson', '22/11/1982', 'The Avengers'] ); |
En este caso, el poder jugar con el valor de this y además asociar una serie de datos a través de un array, permite una poderosa flexibilidad a la hora de escribir código reutilizable.
Conclusión
El valor de this ha sido siempre difÃcil de manejar en Javascript. Las pequeñas diferencias que presenta frente a otros lenguajes asà como un error en su diseño, lo hacen francamente especial. Sin embargo, esa peculiaridad, es precisamente la que permite crear un tipo de código muy versátil una vez que conocemos sus secretos.
Manejarlo correctamente es una parte esencial dentro del desarrollo de aplicaciones complejas en Javascript.

No hubiera podido explicarlo mejor. Excelente entrada!!
Exelente articulo
Explicación de la Madre
Excelente articulo
Hola Carlos, en el apartado “Accediendo a los valores de un objeto desde el propio objeto”, sÃmplemente es que está mal definida la propiedad, en realidad habrÃa que escribirla (para que sea una propiedad como se pretende) asÃ:
var foo = { name: 'Megan', lastName: 'Fox', get completeName() { return this.name + ' ' + this.lastName; } };en este caso serÃa de “sólo lectura”, si se desea que sea asignable, podrÃa añadirse algo como:
set completeName(_completeName) { var mx = /^([^ \t]+)[ \t]?(.*)$/.exec(_completeName); this.name = mx[1]; this.lastName = mx[2]; }ahora podemos hacer algo como
Saludos ¡y gracias por los post!
Gracias por el aporte Jose Juan
Efectivamente, hay que recordar que Javascript incorporó la posibilidad de hacer ‘getters’ en su versión 1.8.5 y que cualquier navegador que interprete correctamente el ES5 permitirá estas operaciones.
Desgraciadamente, como tantas otras veces, tenemos que tener en cuenta que en los navegadores más antiguos, esta solución no funciona. EstarÃamos hablando de IE6, IE7 e IE8.
No obstante, como aquà hablamos del lenguaje y no de sus implementaciones, tu comentario tiene todo el sentido.
Saludos!
var name = "Strange World"; var myApp = function(){ var that = this; // Work around! var name = "World" var sayHello = function(){ console.log( 'Hello, ' + that.name ); }; sayHello(); }; myApp(); // Hello, WorldLa ejecución de myApp(); va a seguir dando “Hello, Strange World”, ya que ‘var name= “World”‘ está declarada como variable “privada”.
Si quisieramos un “Hello, World” en ese ejemplo, deberÃamos hacer un console.log(‘Hello, ‘ + name);.
Si me equivoco, corregidme.
Hola!!
Primero de todo, felicitarte por tu blog (no lo conocia y lo he devorado en poco menos de un mes), y por “tu culpa” he tenido que rediseñar un par de veces mi proyecto.(Los articulos sobre patrones me han sido de gran utilidad, muchas gracias)
Mi proyecto es cMox, un framework para desarrollar juegos en HTML5(Canvas)/Javascript adaptados tanto a la web como a los dispositivos moviles (Phonegap). He usado un patron parecido a Jquery para desarrollar la biblioteca cMox, y con esta programar mi primer juego que ya está disponible online o para descargar en Android (Proximamente iPhone)
http://www.timemox.com/juegos.php
La principal dificultad ha sido optimizar el rendimiento del refresco de Canvas para dispositivos moviles poco potentes (PC=40FPS, movil=12FPS). Al final, he consiguido que funcione a velocidades razonables (20-25 fps) usando lo que yo llamo ‘DobleCanvas’ (Dos Canvas superpuestos, en el primero dibuja objetos estaticos y en el segundo los dinamicos)
Ahora, con cMox medio encarrilado, espero realizar juegos con cierta frecuencia, y en cuanto corrija algunos bugs, liberar cMox y hacer un manual de uso.
Muchas gracias!!
Hola excelente post!
ahora tengo algunas dudas, porque al crear una variable sin “expresamente crearla”, ésta parece formar parte del objeto al que que la contiene o sea:
var myApp = function(){
world_type = ” Cruel ” // no-expresamente un var
var name = “World”
var sayHello = function(){
console.log( ‘Hello, ‘ + this.world_type + this.name );
};
sayHello(); // Invoke the function
};
myApp(); // Hello, Cruel
bueno, la variable world_type parece “pertenecer” al objeto (Function) contenedor, esto es un error de diseño propio de Javascript o algún otro punto oscuro “magico” de Javascript
Gracias !!!
MEGAN FOX jajaja buen articulo amigo
¡Muy buen artÃculo!
Para completar los casos en los que se puede utilizar this agreagarÃa el caso de invocación por constructor. En este caso, this hace referencia al nuevo objeto que retorna dicha invocación. Ej:
function Coordenada() { this.x = 0; this.y = 0; } var origen = new Coordenada(): console.log(origen);Un saludo.
Buen apunte Derik; gracias!