logo blog voltadev
This

This

- views - 02-18-2022

"¿Qué es this en JavaScript?"

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.

Palabra reservada this

this es una palabra que hace referencia al objeto contexto que estamos trabajando


  1. Lo primero que tenemos que entender cuando tenemos javascript en los navegadores:
console.log(this);

this va hacer referencia al objeto global y este objeto se llama window


ecmascript


si ejecutamos este código en node nos va a devolver global que en node sería el objeto global. En node no existe window.


  • Entonces si el objeto global en el navegador es window, esto validaría a true
console.log(this === window); //true

ahora si ejecutamos el siguiente código nos va devolver en consola contexto global

this.nombre = "Contexto global"; //creamos una variable al window
console.log(this.nombre); //Contexto global

⭐ This ejemplos prácticos

A continuación vamos a analizar el comportamiento de this con diferentes ejemplos.

1. Ejemplo:

this.nombre = "Contexto global";
console.log(this.nombre);

function imprimir() {
  console.log(
    this.nombre +
      " sigue imprimiendo la variable global ya que seguimos en el ámbito (scope)"
  );
}

imprimir();
  • Lo primero que realizamos fue crear una variable al window, pero 👀 ojo, sin la necesidad de crear variables con: var, const y let. Pedemos hacer lo siguiente.
this.nombre = "Contexto global";

Aquí podemos apreciar que le asignamos un nombre ▶️ Contexto global esto sería window en nuestro archivo.

Luego de esto, podemos ver en la consola del navegador que después de todas las propiedades y metodos tenemos a Contexto global


ecmascript


Luego de esto creamos la función y la invocamos para imprimir este nombre
function imprimir() {
  console.log(
    this.nombre +
      " sigue imprimiendo la variable global ya que seguimos en el ámbito (scope)"
  );
}

imprimir();

Conclusiones

  • Al ejecutar imprimir, sigue imprimiendo Contexto global por que estamos en el ámbito general "en window para los navegadores".
  • Así que sigo imprimiendo el contexto global al ejecutar la función imprimir()

2. Ejemplo:

Ahora vamos analizar donde se esta ejecutando el this.name dentro de mi const obj

this.nombre = "Contexto global";

const obj = {
  name: "Contexto Objeto",
  imprimir: function () {
    console.log(this.name);
  },
};

obj.imprimir();

Vemos que this se esta ejecutando dentro del scope de la propiedad imprimir apuntando name: "Contexto Objeto", la función anónima ha sido creada dentro del contexto del objeto, por eso a la hora de llamar al método

obj.imprimir();

me marca Contexto Objeto y no Contexto global.


Cuando nos referimos al Contexto global sería la variable que asignamos al window

3. Ejemplo:

Antes de comenzar tenemos que tener en cuenta que esto en JavaScript es un Scope o ambito.

{
  //bloque
}

Vamos a crear un obj2 👀 pero ojo, la propiedad imprimir del obj2 va va hacer referencia a la función que tenemos declarada en el scope global del archivo que es imprimir().

console.log(this);

this.name = "Contexto global";
console.log(this.name);

function imprimir() {
  console.log(this.name);
}

imprimir();

const obj = {
  name: "Contexto Objeto",
  imprimir: function () {
    console.log(this.name);
  },
};

obj.imprimir();

const obj2 = {
  name: "Contexto Objeto 2",
  imprimir // asigne como valor una función que ya estaba declarada
};

obj2.imprimir();

Recordemos a los Shorthand Method Names de los objetos si el nombre de la propiedad y el nombre de la variable o método que guarda el valor es el mismo, simplemente lo podemos omitir.

Sin shorthand

const obj2 = {
  name: "Contexto Objeto 2",
  imprimir: imprimir,
};

Con shorthand

const obj2 = {
  name: "Contexto Objeto 2",
  imprimir,
};

Esto es simplificación de sintaxis.

Conclusiones

  • Resumen del ejemplo, simplemente asignamos una función que ya estaba declarada
  • Como esta función imprimir() ya esta asignada al obj2. El contexto en donde se encuentra en este caso es this.nombre es el contexto de la propiedad imprimir que aplicamos con el shorthand

4. Arrow Function

¿ Que pasa si en lugar una función anónima mejor utilizamos las arrow function ?

this.name = "Contexto global";
console.log(this.name);

function imprimir() {
  console.log(this.name);
}

imprimir();

const obj = {
  name: "Contexto Objeto",
  imprimir: function () {
    console.log(this.name);
  },
};

obj.imprimir();

const obj2 = {
  name: "Contexto Objeto 2",
  imprimir, // asigne como valor una función que ya estaba declarada
};

obj2.imprimir();

// comportamiento con arrow function
const obj3 = {
  name: "Contexto Objeto 3",
  imprimir: () => {
    console.log(this.name);
  },
};

obj3.imprimir();

Esto son los console.log() del código anterior pero nos vamos a enfocar en obj3 que tiene un arrow function


this


  • Este es el console del obj3 al invocar la arrow function linea 42:
    • Contexto global

Aquí hay un detalle, hasta cierto punto las arrow function soluciona pero también crea conflictos. Aquí lo que hace una arrow function, es mantener un enlace del contexto que ha sido creado el objeto donde aparece, a diferencia de esta función anónima, que es una función como tal, maneja su propio scope.

const obj = {
  name: "Contexto Objeto",
  imprimir: function () {
    console.log(this.name);
  },
};

obj.imprimir();

Las arrow function no manejan su propio scope

El contexto de la palabra this, lo que hace es tomarlo directamente del padre del objeto en el que se ha creado es por eso que esta imprimiendo el contexto global. Esto enlaza el contexto de padre al hijo, es muy similar a lo que hace el método bind, de hecho el método call apply y bind están muy relacionados al método this, entonces esa es una de las características por las cuales cuando estás trabajando en la creación de un objeto y dentro de ese objeto tienen propiedades, tienes métodos y esos métodos van a interactuar con propiedades de objeto literal. NO se recomienda que utilices arrow function si no utilizas funciones anónimas.


¿ Por qué ?


Las arrow function no crean un scope, se salta el scope en que ha sido creado, obedece al contexto global en el cual ha sido creado el objeto

Por eso es que obj3.imprimir(); en este caso como obj3 ha sido creado en el contexto global, por eso que nos esta imprimiendo:

  • 🌟 Contexto Global
  • 🌟 obj3 fue creado en dicho contexto
  • 🌟 las arrow function no generan scope a diferencia de las funciones anónimas

5. función constructora que crea su propio scope

Vamos a crear una función constructora que se va llamar Persona, persona va recibir un nombre dentro, le vamos a decir this.nombre = nombre;

Luego vamos a retornar el console.log(this.nombre); en parte final del código a una variable le asignamos una instancia de Persona y le pasamos un nombre como argumento.

this.name = "Contexto global";

function Persona(nombre) {
  this.nombre = nombre;
  return console.log(this.nombre);
}

let kyo = new Persona("Kyo");

Que pasa si en vez de retornar el console.log() su ejecución, probamos otra sintaxis pero antes:

👀 Recordemos que las funciones son ciudadanos de primera clase sirven para crear:


  • objetos
  • prototipos
  • se pueden pasar como parametros
  • las podemos retornar como el resultado de otra función

Eso en el mundo de la programación en javascript se conoce como clausura o closure porque estamos envolviendo un función dentro de una función y la estamos retornando.

retomando lo que vamos a retornar dentro de Persona, vamos crear una función anónima y la mandamos en el return, luego esa función ejecuta la linea del console.log()

this.name = "Contexto global";

function Persona(nombre) {
  this.nombre = nombre;
  // return console.log(this.nombre);
  return function () {
    console.log(this.nombre);
  };
}

let kyo = new Persona("Kyo");

Vemos que esto es solo la declaración de una función anónima

return function () {
  console.log(this.nombre);
};

para que esto se invoque yo tendriamos que ejecutar la instancia de Persona, que este caso es la variable kyo

kyo();

vamos a ejecutarla como método, porque finalmente esta retornando un función

this.name = "Contexto global";

function Persona(nombre) {
  this.nombre = nombre;
  //return console.log(this.nombre);
  return function () {
    console.log(this.nombre, "return f()");
  };
}

let kyo = new Persona("Kyo");
kyo();

Vamos a ver que me retorna en consola

Contexto global

Ahora ¿ por qué me está diciendo Contexto global ?

Recapitulemos que cada función crea un contexto salvo las arrow function que heredan el contexto en el cual ha sido creada.

  • ¿ Que pasa aquí ? la función constructora tiene su propio scope y le estoy pasando como argumento un nombre
  • Dentro de la función constructora estoy asignando una variable, this.nombre = nombre; es igual al nombre que recibe como parámetro

Entonces cuando ejecutamos este directamente al return si existe

return console.log(this.nombre);

Esta nueva función anónima crea un nuevo scope, crea un nuevo contexto internamente, no tiene ninguna propiedad nombre

return function () {
  console.log(this.nombre, "return f()");
};

Entonces como no tiene un propiedad nombre, lo único que hace es regresar y leer el this del Contexto Global por eso en consola nos muestra Contexto global en lugar de Kyo

¿ Cuál sería la solución con Ecmascript 2015 en lugar de tenerlo en una función anónima ?

🧠 Recordemos que las arrow function no crean scope interno

Entonces en lugar de retornarlo como una función anónima la retornamos como una arrow function

return () => console.log(this.nombre, "return f()");
this.name = "Contexto global";

function Persona(nombre) {
  this.nombre = nombre;
  //return console.log(this.nombre);
  return () => console.log(this.nombre, "return f()");
}

let kyo = new Persona("Kyo");
kyo();

Antes de las que existieran las arrow function de esta forma los solucionamos

Usábamos var, pero ahora como tenemos const lo vamos aplicar con const, ya que con var es mala práctica. Vamos a crear una constante que se va llamar that


  • that va hacer referencia al this de la función constructora

Cuando miramos esto en código, sacamos la conclusión de que lo que quiso hacer es guardar el contexto this de esta función constructora para que si después retornas una función anónima, puedas recuperar ese this

function PersonaTwo(nombre) {
  const that = this; // es igual al this de la función
  that.nombre = nombre;
  //return console.log(this.nombre);
  return function () {
    console.log(that.nombre, "that solution");
  };
}

let asuka = new PersonaTwo("Asuka");
asuka();

¡Muchas gracias por tu lectura dejo el link de cafecito apoyo voluntario, tu contribución me motiva a seguir creando contenido de alta calidad. ¡Muchas gracias por tu apoyo!


Buy Me a Coffee at ko-fi.com