La variable this en Javascript difiere un poco con respecto a otros lenguajes, en este artículo analizamos this y sus variantes en el contexto donde se use.
En el hangout que realizamos, dedicado a las "buenas prácticas en el lenguaje Javascript" vimos varios puntos interesantes que ahora estamos transcribiendo en artículos. Éste es el segundo que publicamos, siendo que el primero se dedicó a tratar la sobrecarga de funciones Nos lo ofreció nuestro compañero Eduard Tomàs, que siempre nos obsequia con grandes joyas de conocimiento.
En los lenguajes de programación más "tradicionales", la variable "this" siempre tiene un valor clarísimo. Sin lugar a dudas, "this" siempre contiene la referencia al objeto sobre el que se está ejecutando un método. Todos los métodos se ejecutan en el contexto de un objeto (esto en términos de programación orientada a objetos) y "this" apunta a este objeto. Sin embargo, en Javascript no es así.
En Javascript, buscando por muchos sitios realmente se encuentran definiciones de "this" un poco complicadas de entender. Te dicen que es "el propietario de la función"... y en caso que no exista propietario, te dicen que "this" es el "objeto global".
Dicho con otras palabras, que podemos encontrar en literatura Javascript, "this es el contexto de una función". Una de las cosas interesantes de Javascript y muy potentes es que el contexto se puede modificar y depende de como se invoca esa función. Repetimos: el valor de "this" dentro de una función no depende de cómo se define esa función, sino de cómo se invoca.
Si yo coloco código fuera de cualquier función y trato de ver el contenido de this, encontraré el contexto global. Puedes probarlo con una línea como esta:
console.log(this); Si estás en un navegador encontrarás que te manda a la consola el contenido del objeto "window".
Propietario de la función
Si ahora escribes el código de una función y dentro accedes a "this", lo que encontrarás es el "propietario de la función". Pero esto del "propietario" es un poco complicado de entender, porque básicamente pueden ocurrir dos cosas:- Si la función se ejecuta como global, "this" será el propio objeto global.
- Si la función se ejecuta como método de un objeto, entonces "this" es el objeto que está recibiendo este método.
Pero luego existen mecanismos para cambiarlo, como veremos también.
Error típico en Javascript
Ahora veamos un código que podemos encontrarnos por ahí que podría resultar en otros lenguajes correcto, pero que en Javascript denota que el programador no entiende bien que "this" puede apuntar a varias cosas.//esto estaría conceptualmente mal var obj = { nombre: "Edu", apellidos: "Tomas", completo: this.nombre + " " + this.apellidos } console.log(obj); //nos mostrará en consola //Object { nombre="Edu", apellidos="Tomas", completo="undefined undefined"}
Como ves, hemos definido un objeto con la "notación de objeto Javascript" conocida como JSON habitualmente. La propiedad completo, a la que aparentemente se habría asignado el nombre concatenado con los apellidos, en realidad nos queda como "undefined undefined". Esto es porque en ese lugar, "this" es el objeto global, ya que no se ha ejecutado dentro de una función como método de un objeto.
Eso se podría haber "arreglado" convirtiendo a "completo" en una función que devuelve esa concatenación:
var obj = { nombre: "Edu", apellidos: "Tomas", completo: function(){ return this.nombre + " " + this.apellidos; } } console.log(obj.completo()); //nos mostrará en consola "Edu Tomas"
Luego si invocamos a la función completo como método del objeto, "this" sí que será la instancia del objeto sobre el que se llamó al método.
Funciones call / apply / bind
Para terminar de liarlo, vienen tres funciones "muy divertidas" que son "call()", "apply()" y "bind()". Estas funciones las veremos con detalle más adelante, cuando veamos otros aspectos de Javascript, pero básicamente, "call()" y "apply()" sirven para invocar una función pero en la que se suministra un valor de "this" que sustituirá al valor que hubiera tomado en otra situación.Dicho de otra manera, en la ejecución de una función, el valor de "this" no será el que tocaría, sino el que será el valor que tú le indiques en la llamada a "call()" o "apply()".
Por su parte, "bind()" es un método muy curioso que para empezar, no devuelve un valor, sino que devuelve otra función. Cuando invoco esta otra función que devuelve, el valor de "this" dentro de ella, es el valor original que yo había pasado al invocar a "bind()".
Esto es difícil verlo sin un pedazo de código y aunque más adelante queremos ver "bind()" con mayor detalle, creo que estaría bien echar un vistazo:
function bindeando(){ console.log(this); } bindeando.bind("hola!!")();
Conclusiones
- El valor de this no es el clásico que todos tenemos en mente en otros lenguajes de programación como podrían ser PHP, Java, C#, C++...
- No puedes saber el valor que tendrá la variable "this" al ver el código de una función, porque depende de cómo te hayan invocado a esa función.
Más adelante veremos más detalles de "this" y las funciones "call()", "apply()" y "bind()", pero recuerda que este material lo tienes en el evento en vivo "#jsIO Buenas prácticas en el lenguaje Javascript" y en este artículo nos hemos quedado en el minuto 27 de esa presentación.
Eduard Tomàs
Apasionado de la informática, los videojuegos, rol y... la cerveza. Key Consulta...