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
Top comments (0)