JavaScript internals - This y el Contexto de ejecución
gugadev
Posted on April 6, 2019
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() { ... }
}
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()
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()
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
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
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 😉
Posted on April 6, 2019
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.