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