JavaScript internals - This y el Contexto de ejecución

gugadev

gugadev

Posted on April 6, 2019

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 😉

💖 💪 🙅 🚩
gugadev
gugadev

Posted on April 6, 2019

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related