> Manuales > Manual de JavaScript

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.

La palabra this y el contexto en Javascript

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í.

Consulta el Manual de Programación Orientada a Objetos saber más de 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".

Nota: Cuando ejecutas Javascript dentro de una página web, o sea, en un navegador, el objeto global es el objeto "window", a partir del que cuelgan todos los objetos de la jerarquía. Sin embargo, en NodeJS que se ejecuta en una máquina como un lenguaje de programación de propósito general, el objeto global es otra cosa. También existe un objeto global en NodeJS, que tiene una serie de funciones, que hace el rol del objeto "window". Obviamente, en ese objeto global de NodeJS tengo cosas muy distintas de las que encuentras en "window" en un navegador, pero también existe un "contexto 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:

  1. Si la función se ejecuta como global, "this" será el propio objeto global.
  2. 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.

Nota: Te devuelve undefinded porque en el contexto global (objeto "window" teniendo en cuenta que eso se ejecutase en un navegador) "window.nombre" no existe y tampoco "window.apellidos" y si accedemos a una propiedad inexistente de un objeto, Javascript nos devuelve el valor "undefined".

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()".

Nota: Tener siempre en cuenta que Javascript es un lenguaje tipo "funcional" (por decirlo de alguna manera), en el que las funciones son ciudadanos de primer orden. El tipo de datos "función" es tan valido como puede ser "string", "object", "number"... Esi significa que puedo pasar funciones como parámetro y puedo devolver funciones como valores de retorno.

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

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...

Manual