¿Qué es “this”?
El objeto <ins>contexto</ins> de JavaScript en el cual se está ejecutando el código actual (esto no dice mucho ahora, lo irás entendiendo a medida que vayas conociendo su comportamiento).
¿Por qué existe “this”?
¿A qué está haciendo referencia “this” cuando lo uso?
Esto lo puedes responder con ayuda de otra pregunta… ¿Dónde se invocó la función que usa “this”? ¡Hagámoslo simple! Piensa en “this” como un parámetro más de la función, cambiará de acuerdo a cómo la función sea llamada.
¿El método se llama a través de un objeto?
const persona = {
nombre: 'Platzinauta',
edad: 100,
saludar() {
alert(`Hola, mi nombre es ${this.nombre}`)
}
}
persona.saludar() // Hola, mi nombre es Platzinauta
El “this” estará definido implícitamente, sólo hay que mirar a la izquierda del punto que llama al método para encontrar al objeto al que está haciendo referencia “this” (en este caso, persona
).
¿Y si es un objeto literal complejo? ¡No importa! Aplica la misma regla (<ins>mirar lo que está inmediatamente a la izquierda del punto</ins>):
const persona = {
nombre: 'Platzinauta',
edad: 100,
saludar() {
alert(`Hola, mi nombre es ${this.nombre}`)
},
padre: {
nombre: 'Freddy',
saludar() {
alert(`Hola, mi nombre es ${this.nombre}`)
}
}
}
persona.saludar() // Hola, mi nombre es Platzinauta
persona.padre.saludar() // Hola, mi nombre es Freddy
Y, ¿si es una función independiente que no está asociada a ningún objeto pero usa “this”?
functionsaludar(){
alert(`Hola, mi nombre es ${this.nombre}`)
}
const persona = {
nombre: 'Platzinauta',
edad: 100,
}
En este caso, el “this” se debe referenciar explícitamente, haciendo uso del método de JavaScript call
:
saludar.call(persona) // Hola, mi nombre es Platzinauta
Si la función saludar()
recibiera parámetros, después de la referencia para “this” en los paréntesis de call
se pueden pasar los parámetros:
saludar.call(persona, parametro1, parametro2, parametroN)
El método call
de JavaScript tiene un hermano llamado apply
; puedes usar uno u otro, pero si en algún momento tu función recibe un <ins>array como parámetro</ins>, apply
recibe al array y lo descompondrá (mientras que call
no puede recibir un array como parámetro, tocaría pasarle cada elemento de forma individual).
No quiero usar ni call
ni apply
, pero mi función tiene “this”, ¿qué puedo hacer?
¡No te preocupes! Hay un tercer método miembro de la familia llamado bind
. A diferencia de sus hermanos, bind
no invocará la función de inmediato, sino que te retornará una nueva para que la puedas invocar cuando quieras, con la referencia a “this” que tú elijas:
functionsaludar(){
alert(`Hola, mi nombre es ${this.nombre}`)
}
const persona = {
nombre: 'Platzinauta',
edad: 100,
}
const saludoPlatzi = saludar.bind(persona) // Definimos que "this" hará referencia a "persona", y esa función se podrá ejecutar a través de "saludoPlatzi".
saludoPlatzi() // Hola, mi nombre es Platzinauta
OJO 👀 : Si tu función recibe un array como parámetro, la mejor opción es apply
; si por alguna razón quieres usar call
o bind
, los elementos del array deberán pasarse uno a uno.
Pero, ¿qué pasa si defino una clase y creo instancias de esa clase, en vez de objetos literales?
classPersona{
constructor(nombre, edad) {
this.nombre = nombre
this.edad = edad
}
}
const platzinauta = new Persona('Platzinauta', 100)
La palabra reservada new
definirá la referencia del “this”, a la instancia que se crea en cada sentencia.
¡Mucha información! 😑 No desesperes, no falta mucho más para que seas un experto en “this”…
¿Qué sucederá si llamo a la función y no uso ninguno de los métodos de la querida familia vista previamente? (call
, apply
, bind
)
¡El “this” hará referencia al contexto donde se llama la función! Si la función está ahí, sola, como pan que no se vende 🍞, si no está dentro de una clase, o un objeto literal, o dentro de otra función, quiere decir que está en el contexto global, por lo que “this” hará referencia al objeto global, es decir, ¡<ins>window</ins>!
functiondecirEdad(){
alert(`Hola, mi edad es ${this.edad}`)
}
const persona = {
nombre: 'Platzinauta',
edad: 100,
}
saludar()// Hola, mi edad es undefined
¿Undefined? ¿Por qué? Porque el objeto global window no tiene ningún atributo de edad 😄
Acaso, ¿se puede complicar más? ¡Si! Mentira, ¡no!… Solo hay un caso más, pero en vez de complicar las cosas, ayuda mucho a trabajar con “this”, y es el caso especial de las arrow functions ➡️. Si pasamos una función, como parámetro de otra función, el contexto de ejecución de la función pasada como parámetro será la función que la recibe, lo que muchas veces se traduce a la nada…
Para evitar que el contexto de la función parámetro sea el limbo, en vez de usar una función normal, podemos usar una arrow function ➡️, y la razón es muy sencilla, ¡<ins>las arrow functions no generan un nuevo contexto de ejecución</ins>! Por lo que, al pasar una arrow function como parámetro de otra función, el contexto de ejecución de la arrow function será el mismo de la función que la recibe como parámetro.
Ahora ya conoces todos los detalles de “this”, siéntete orgulloso de ti mismo por haber llegado hasta aquí, esto es algo que todo desarrollador de JavaScript debería conocer y entender.
Para terminar, te dejo este artículo de MDN, donde se exponen más detalles de “this”.
¡Saludos!