Aprende qué tiene de particular el uso de this en Javascript con respecto a otros lenguajes de programación. Entiende los distintos valores de this dependiendo del contexto donde se use.
Hemos realizado una charla recientemente en nuestro canal de Youtube dedicada a las "buenas prácticas en el lenguaje Javascript". Allí 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 exceptuando los métodos estáticos, en los que no puede accederse a this) y "this" apunta a este objeto. Sin embargo, en Javascript no siempre es así.
this
y otros conceptos sobre este paradigma.
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.
this como el objeto global
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".
This como el propietario de la función Javascript
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.
Por ejemplo, si tenemos este código tal cual en una página web, fuera de cualquier función u objeto:
function miFuncion() {
console.log(this);
}
miFuncion();
Veremos que el valor de this
en este caso resulta ser el objeto window.
Tiene sentido que sea el objeto window porque en el javascript del navegador, toda declaración global (como esta función) se adjunta como propiedad del objeto window. Por tanto, el propietario de una función global viene a ser el objeto global, o sea, window. Esto quiere decir, que a la función podríamos haberla invocado también como window.miFuncion()
, dado que pertenece al objeto window. Son esas cosas raras de Javascript que cuando las entiendes no te parecen tan extrañas.
Ahora vamos a ver cómo this
cambia en el caso que el propietario de una función sea un objeto. Tenemos el siguiente código:
let miObjeto = {
prop: 'valor',
metodo: function() {
console.log(this);
}
}
miObjeto.metodo();
Al ejecutarse podrás ver que en la consola el valor de this
que se muestra es el propio objeto "miObjeto
".
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.
this en los manejadores de eventos
Otro caso interesante de la referencia this
en Javascript es cuando definimos manejadores de eventos. En ellos la palabra this
hace referencia al objeto sobre el cual se ha configurado el manejador de evento.
Esto lo podemos ver muy claramente con un ejemplo de manejador de evento, como en el código siguente.
document.addEventListener('mousemove', function() {
console.log(this);
});
Hemos definido un manejador para el evento 'mousemove' sobre el objeto document. Esto hará que cada vez que se mueva el ratón por encima del documento mostrará el valor de this
en la consola. Si lo ejecutas podrás apreciar que el valor que aparece es el objeto document
de la página.
Nuevamente, tiene sentido porque en este caso podemos pensar que el propietario de una función definida como manejador de eventos sobre un objeto dado, es el propio objeto. Es decir, en este caso el manejador definido sobre el objeto document, tendría como propietario al objeto document. Por tanto, this
contendrá una referencia al objeto document.
Si nuestro manejador de eventos se hubiera colocado en un botón de la página, this
haría referencia a ese botón de la página, dado que sería el propietario de la función manejadora.
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()". y en este artículo nos hemos quedado en el minuto 27 de esa presentación.
Vídeo de Buenas prácticas en Javascript
Acabamos compartiendo el vídeo del que hemos extractado la información contenida en este artículo sobre la palabra this
en Javascript. Esperamos que os guste esta charla.
Eduard Tomàs
Apasionado de la informática, los videojuegos, rol y... la cerveza. Key Consulta...