Entendiendo el significado de ‘this’ en JavaScript

Uno de los conceptos más confusos de JavaScript es el keyword this. El valor de this es dinámico y depende del contexto de la función.

Voy a tratar de resumir con sencillos ejemplos el significado de this.

Contexto Global

En el contexto global this es igual a window, y toda variable declarada será global y formará parte del objeto window. Así pues tanto window.message como this.message tendrán el mismo valor.

Un ejemplo:

var message = "Hello";

console.log(window.message); // Hello
console.log(this.message); // Hello

Contexto de función

Dentro de una función el valor de this, como en el anterior caso, sigue siendo igual al objeto window.

var message = "Hello";

var sayHello = function() {
    console.log(this);
    console.log(this.message);
}

sayHello(); // Window object, Hello 

Método de un objeto

En esta situación no podemos saber el valor de this hasta ver de que manera se invoca al método del objeto. En el siguiente ejemplo tenemos un variable global, message, con el valor Hello (message es una propiedad del objeto window). A continuación se declara el objeto, obj, con una propiedad message con valor World y un método sayHello.

En resumen:

  • message es igual a Hello o window.message es igual a Hello.
  • obj.message es igual a World.
  • obj.sayHello es igual a una función.

Ahora declaramos una nueva variable, fn, donde dejamos la función obj.sayHello. Si ejecutamos la variable fn como función, es decir fn(), obtenemos el valor Hello. Esto es debido a que fn() no tiene receptor por lo que this.message será referenciado al objeto global window.message.

Sin embargo si ejecutamos obj.sayHello(), estamos indicando que el objeto, obj, es el receptor de la función sayHello(). Este receptor es igual a this por lo que el valor de this.message será igual a obj.message, es decir World.

Os dejo el ejemplo del que os hablaba:

var message = "Hello";

var obj = {
    message: "World",
    sayHello: function() {
        console.log(this.message);
    }
}

var fn = obj.sayHello;
fn(); // Hello

obj.sayHello(); // World

Función anidada

A tener en cuenta que cada función se ejecuta en un contexto diferente, por lo que cada función tiene su propio this.

A partir del ejemplo anterior, vamos a añadir dentro del método sayHello del objeto obj, una función sayHello_fn. Tras declarar la función la ejecutaremos como sayHello_fn().

Al igual que en el ejemplo anterior, dejar la función obj.sayHello en una variable fn y ejecutarla después como fn(), nos devolverá Hello ya que no tiene receptor.

A diferencia del ejemplo anterior, ejecutar obj.sayHello() también devolverá Hello. Esto es debido a que:

  • Dentro de sayHello() se ejecuta sayHello_fn(), el valor de this es igual a window ya que sayHello_fn() se ejecuta en un contexto diferente.

Como dirían los maestros de redradix:

  • Cada función tiene su propio this.
  • Las funciones anidadas no comparten el receptor.
  • El valor de this depende de la invocación, no de la definición.

Aquí el ejemplo:

var message = "Hello";

var obj = {
    message: "World",
    sayHello: function() {
        var sayHello_fn = function() {
            console.log(this.message);
        }
        sayHello_fn();
    }
}

var fn = obj.sayHello;
fn(); // Hello

obj.sayHello(); // Hello

Podemos controlar los contextos de ejecución de las funciones con call() y apply() pero esto lo dejo para otra ocasión.

Espero haberos aclarado un poco más el confuso significado de this y si no, están abiertos los comentarios para cualquier duda, corrección o sugerencia que queráis hacerme ;-)