¿Qué es This en JavaScript?
Tags: javascript, this
Published: 2020-11-20 03:03:44

En general, el concepto de this, se aplica a una referencia a una instancia actual de la clase en la que aparece, esta referencia esta disponible en muchos lenguajes de programación, pero en el caso de javascript tiene algunas casuísticas más particulares.

Por regla general this es una referencia que se crea cuando una función que es invocada, y su valor depende de el lugar en el cual esta invocación se realice.

**Ámbito Global**

Si esta invocación no es llamada desde una función, this siempre hace referencia al objeto window

```
console.log(this);
```
```
Window {window: Window, self: Window, …}
```
**Funciones**

En el caso de las funciones, el valor de this, dependerá exclusivamente de el lugar en el cual esta es invocada.

por defecto, dentro de una función, this hace referencia al objeto global window

```
function test(){
  console.log(this);
}

test();
```
```
Window {window: Window, self: Window, …}
```

Nuestro escenario cambia totalmente si usamos "use strict"

```
"use strict"

function test(){
  console.log(this);
}

test();
```
```
undefined
```

El uso estricto nos ayuda a no modificar el ámbito global accidentalmente, por ejemplo:

```
function Cuadrado(ancho, alto) {
    this.ancho = 100;
    this.alto = 200;
}

const cuadrado = Cuadrado(50,60);
console.log(cuadrado); 
```
```
undefined
```
pero si vemos el valor de las variables dentro del objeto window

```
console.log(window.ancho,window.alto)
```
```
100,200
```

para prevenir esto, se necesita el uso de "use strict" 

```
"use strict"
function Cuadrado(ancho, alto) {
    this.ancho = 100;
    this.alto = 200;
}

const cuadrado = Cuadrado(50,60);
console.log(cuadrado); 
```
```
Uncaught TypeError: Cannot set property 'ancho' of undefined 
```
no permitiendo modificar el valor de this en su ámbito local

En cambio, si agregamos a la declaración la palabra new, generamos una nueva instancia de this

```
"use strict"
function Cuadrado(ancho, alto) {
    this.ancho = 100;
    this.alto = 200;
}

const cuadrado = new Cuadrado(50,60);
console.log(cuadrado); 
```
```
Object {
  alto: 200,
  ancho: 100
}
```
Ahora si la invocación la realizamos en el constructor del objeto
```
"use strict"
function Cuadrado(ancho, alto) {
    this.ancho = ancho;
    this.alto = alto;
    console.log (this);
}

const cuadrado = new Cuadrado(50,60);
```
```
Object {
  alto: 60,
  ancho: 50
}
```

**Métodos**

Cuando llamamos a un método de una función, this se asocia al objeto que contiene dicho método

```
const cuadrado = {
    ancho: 100,
    alto: 200,
    info() {
        console.log('Soy un cuadrado de',this.ancho, 'x',this.alto);
        console.log(this);
    }
};
cuadrado.info();
```
```
Soy un cuadrado de 100 x 200
Object {ancho: 100, alto: 200, info: ƒ...}
```
Ahora todo cambiaría, si asignamos el método a una declaración de función

```
const cuadrado = {
    ancho: 100,
    alto: 200,
    info() {
        console.log('Soy un cuadrado de',this.ancho, 'x',this.alto);
        console.log(this);
    }
};
let mostrarInfo = cuadrado.info;
mostrarInfo();
```
```
Soy un cuadrado de undefined x undefined
Window {window: Window, self: Window, …}
```
Acá perdemos el contexto de this, ya que la llamada ocurre bajo el ámbito global

**Arrow Functions**

Al momento de crear un arrow function, el valor de this quedará asociado al valor de this de su ámbito externo

```
const test = () => {
    console.log(this);
};
test(); 
```
```
Window {window: Window, self: Window, …}
```

Antes de usar arrow functions, para poder manejar los valores del ámbito global dentro de métodos, debíamos usar un "hack" que era copiar el valor de this a otra variable

```
const cuadrado = {
  ancho: 100,
  agrandar() {
    const _this = this;
    setInterval(function () {
      console.log(++_this.ancho);
    }, 1000);
  }
};
cuadrado.agrandar();
```

Solucionar esto con el uso de arrow function es mucho más limpio

```
const cuadrado = {
  ancho: 100,
  agrandar() {
    setInterval(() => {
      console.log(++this.ancho);
    }, 1000);
  }
};
cuadrado.agrandar();
```

**Bind**

Existen adicionalmente, métodos que nos permiten modificar la referencia a donde apunta this

Veamos este ejemplo

```
const cuadrado = {
  ancho: 200,
  alto: 100,
  showDimensions: function() {
    return this.ancho + ' x ' + this.alto;
  }
}

const print = function() {
  console.log(this.showDimensions());
}

print();

```
```
Uncaught TypeError: this.showDimensions is not a function
```

this en la función print apunta a la referencia del objeto en el ámbito global, ergo no tiene acceso a showDimensions

En caso que necesitemos acceder al scope de cuadrado desde print necesitamos usar el método bind()

```
const printBinded = print.bind(cuadrado);
printBinded();
```

De esta forma, le estamos diciendo que el valor de this en print, debe ser la referencia al de cuadrado

**Call**

La diferencia con Bind, es que este método, si ejecuta la función, igual que (), con la diferencia que Call tiene como parámetro la referencia de this en la función que se ejecuta.

```
const printBinded = print.bind(cuadrado);
printBinded();

```
Con este obtendremos el mismo resultado que con Bind, con la diferencia que la función no se copia, si no que se ejecuta.

**Apply**

La diferencia entre Call y Apply, es tan solo la forma de enviar los parámetros, en el caso de apply esta orientado a recibir muchos parámetros, en forma de array

```
print.apply(cuadrado, ['100', '200']);
```
**Borrowing**

Un préstamo de función es cuando compartimos la función de un objeto, pero con distintos parámetros

```

const cuadrado = {
  ancho: 100,
  alto: 200,
  showDimensions: function() {
    return this.ancho + ' x ' + this.alto;
  }
}

const rectangulo = {
  ancho: 500,
  alto: 200
}

const result = cuadrado.showDimensions.apply(rectangulo);
console.log(result); 
```
```
500 x 200
```

**Currying**

El concepto de currying es básicamente crear una copia de una función pero con parámetros por defecto

Ejemplo:

```
function showDimensions(a, b) {
  return a + ' x ' + b;
}

const showDimensionsCopy = showDimensions.bind(this, 200);

console.log(showDimensionsCopy(100));

```
```
"200 x 100"
```

cover picture by [@bradstallcup](https://unsplash.com/@bradstallcup)