JavaScript internals - This y el Contexto de ejecución
Tags: javascript, backtothebasics, explainlikeimfive
Published: 2019-04-06 02:52:29

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:

```javascript
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:

```javascript
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:

```javascript
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:

```javascript
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`:

```javascript
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 😉