DEV Community

Cover image for JavaScript internals - This y el Contexto de ejecución
Gustavo Garsaky
Gustavo Garsaky

Posted on

JavaScript internals - This y el Contexto de ejecución

Cuando empezamos a aprender JavaScript y llegamos a la parte de herencia, instancias y métodos, nos topamos con un villano difícil de vencer. Hablo del misterioso this.

Para explicar esto debemos tener en cuenta un concepto importante: contexto de ejecución.

Contexto de ejecución

Piensa en el contexto de ejecución como en una bolsa. Cada una de estas bolsas se compone de tres cosas:

  • Lexical Environment
  • Variable Environment
  • Objeto this

Lexical y Variable environment es lo mismo (salvo casos excepcionales que no discutiré aquí). Dentro de este, se almacenan dos cosas: una referencia opcional al outer scope y un record o registro que mapea dentro de una tabla los identificadores con sus valores.

Para ilustrar mejor este concepto, imaginemos que tenemos el siguiente código:

var boo = 3
function test() {
  var foo = 1
  var bar = 'a'
  function baz() { ... }
}
Enter fullscreen mode Exit fullscreen mode

Cuando se ejecute, se creará una nueva bolsa, cuyo Lexical environment tendrá la siguiente información:

Elemento Valor
record <record table>
parent <global>
Identificador Valor
foo 1
bar 'a'
baz <function>

En este caso, como la función no está dentro de ninguna estructura, parent será el scope global. Si fuese un closure (función dentro de otra), parent sería la función que la contiene. Esto es lo que se conoce como scope chaining y sirve para poder acceder a scopes superiores.

Ententiendo this

Hasta ahora, hemos comprendido qué es lo que ocurre cuando ejecutamos una función. Aprendimos que, cuando eso pasa, se crea un contexto de ejecución que contiene un lexical environment y también una referencia a this. Pero, ¿cómo se define el valor de este objeto?

Para entender de dónde toma this su valor, hay que saber que su valor dependerá de cómo es ejecutada la función en donde se encuentra. A continuación, listo algunos de los escenarios más comunes.

Dentro de una función

Cuando la función no es parte del prototipo de una función constructora, el valor de this será igual al objeto window. Nota que esto es así aunque sea un closure:

function a() {
  var c = function c() {
    console.log(this === window) // <- true
  }
  setTimeout(function b() {
    console.log(this === window) // <- true
  })
  c()
  console.log(this === window) // <- true
}

a()
Enter fullscreen mode Exit fullscreen mode

Dentro en un método

Cuando se usa this dentro de un método, el valor de this será equivalente al elemento en el que se ejecuta al método:

const guy = {
  whoami() {
    console.log(this === guy) // <- true
  }
}

guy.whoami()
Enter fullscreen mode Exit fullscreen mode

Dentro de un constructor o método

En este caso, this siempre hará referencia a la instancia:

function Person() {}

Person.prototype.whoami = function() {
  console.log(this instanceof Person)
}

const person = new Person() // instancia
person.whoami() // <- true
Enter fullscreen mode Exit fullscreen mode

Usando bind, call o apply

Algunas veces necesitamos sobreescribir el valor por defecto de this para hacerlo dinámico; es decir, que pueda hacer referencia a distintos contextos que queramos. Para esto, podemos usar bind, call y apply:

function sayHi(age) {
  console.log(`Hello, i'm  ${this.name} and I have ${age} years old`)
}

const john = { name: 'John Doe' }
const jane = { name: 'Jane Doe' }
const josh = { name: 'Josh Smith' }

sayHi.bind(john)(24) // Hello, i'm John Doe and I have 24 years old
sayHi.call(jane, 23) // Hello, i'm Jane Doe and I have 23 years old
sayHi.apply(josh, [25]) // Hello, i'm Josh Smith and I have 25 years old
Enter fullscreen mode Exit fullscreen mode

Si el último ejemplo te pareció extraño, no te preocupes. En un próximo post nos adentraremos a los tres desconocidos de JavaScript: bind, call y apply.


Conclusión

Espero que con este artículo te haya quedado un poco más claro de dónde sale this y cómo funciona. Además, hemos aprendido un poquito acerca del core de JavaScript para entender qué es lo que pasa "detrás de escenas", lo cual es muy importante para la compresión del lenguaje 😉

Top comments (8)

Collapse
 
jorgeguevarab profile image
Jorge Guevara

Qué bueno encontrar contenido en español.

Collapse
 
gugadev profile image
Gustavo Garsaky

!Hay que apostar por nuestra lengua también!

Un abrazo.

Collapse
 
franwatafaka profile image
Fran Sosa

Guz gracias por el contenido en español! yo estuve pensando en publicar también algo en nuestro idioma pero quizás quedaba desubicado jajaj. Buen post!

Thread Thread
 
gugadev profile image
Gustavo Garsaky

Hola Fran :D Sería cool que más gente publique contenido en Español! Si tienes algo que compartir, ¡dale!

Saludos.

Thread Thread
 
franwatafaka profile image
Fran Sosa

Empecé un blog para ver como me va poniendo en practica lo que estoy aprendiendo de Nuxt... me faltan unos retoques y publico como lo hice y obvio, compartir el blog. ;)

Collapse
 
diek profile image
diek

Buen tuto, estaría guay que avisases de las diferencias entre funciones al uso y las funciones flecha. Ya que contarás sobre el bind, podrías hacer otra entrega.

Collapse
 
gugadev profile image
Gustavo Garsaky

De hecho sí haré un tuto explicando eso, porque ocurre algo especial con el contexto de ejecución en arrow functions ;)

Gracias por comentar, Diego.

Collapse
 
nielsbom profile image
Niels Bom

Where did you get the cover image?