Estás escribiendo JavaScript y de repente te das cuenta con horror y terror de que has escrito una función enorme. Le ha pasado a los mejores de nosotros. Ahora viene el impulso casi imparable de separar la función en piezas más pequeñas.
Las grandes funciones significan muchas responsabilidades en un solo lugar y, posiblemente, también huele a código, por lo que es una buena idea en sí misma. Pero desea dividir la función de tal forma que no pierda su significado o contexto. Para hacer eso, debe pensar en el encadenamiento de métodos, también llamado encadenamiento de funciones. Este artículo explicará lo que quiero decir con eso.
Requisitos previos
Antes de comenzar, aquí hay algunos conceptos de JavaScript con los que ya debe estar familiarizado:
- Funciones de flecha
- Métodos de matriz
- Funciones asíncronas
La mayoría de los desarrolladores experimentados tendrán cierta experiencia con métodos Array
, como mapear, reducir y filtrar. Probablemente ya te hayas encontrado con algo como esto:
const food = ;// This type of usage is very commonfood .map(item => item.type) .reduce((result, fruit) => { result.push(fruit); return ; }, );// result:
El encadenamiento de métodos ocurre cuando desea llamar a varias funciones utilizando el mismo objeto y su referencia. En el ejemplo anterior, el método array map
devuelve un Array
, que tiene un número formidable de métodos.
Debido a que devuelve una referencia que apunta a un Array
, tendrá acceso a todas las propiedades de Array
. Es el mismo principio que usas para encadenar tu propio método.
Mejor comprensión de esto
No cubriré todos los matices de this
, pero es bueno entender por qué this
funciona de la manera que lo hace. No importa cuán experimentado seas, la palabra clave esto puede ser difícil de entender. A menudo es la razón por la que las cosas no funcionan de la manera que esperas que work
Aquí está la esencia de la misma: this
siempre apuntará a la scope
o instancia actual desde donde se llama. Un ejemplo:
const dog = { is: null, log: () => console.log(this.is), bark() { this.is = "woofing"; this.log(); return this; }, walk() { this.is = "walking"; this.log(); return this; }, eat() { this.is = "eating"; this.log(); return this; }};dog .bark() .eat() .walk();
Cuando escribe una función como esta (sin juego de palabras), es posible que desee encadenar métodos que estén relacionados con el objeto. El objeto dog
tiene 3 métodos: walk
, bark
y eat
. Cada vez que llamo a cualquiera de sus funciones, una consola debe mostrar la representación de lo que el perro está haciendo en ese momento exacto.
Pero hay un problema con eso. Si lo ejecuta en el navegador, se dará cuenta de que no funciona como se esperaba. Esto se debe a que las funciones de flecha utilizan el ámbito léxico, donde this
se refiere a su ámbito circundante, en este caso window
, no al objeto en sí.
Para resolver esto, debemos usar una llamada a función anónima para representar la propiedad log
:
// instead of this: log: () => console.log(this.is),// use this: log() { console.log(this.is); }
Ahora el alcance this
del perro va a ser accesible dentro de la función.
Usando Class
Puede lograr el mismo resultado usando clases:
class Dog { is = null; log() { console.log(this.is); } bark() { this.is = "woofing"; this.log(); return this; } walk() { this.is = "walking"; this.log(); return this; } eat() { this.is = "eating"; this.log(); return this; }}const dog = new Dog();dog .bark() .eat() .walk();
Usando Prototype
Si tiene que usar prototype, hágalo de esta manera:
function Dog() {}Dog.prototype.is = null;Dog.prototype.log = function() { console.log(this.is);};Dog.prototype.bark = function() { this.is = "woofing"; this.log(); return this;};Dog.prototype.walk = function() { this.is = "walking"; this.log(); return this;};Dog.prototype.eat = function() { this.is = "eating"; this.log(); return this;};const dog = new Dog();dog .bark() .eat() .walk();
¿Qué Pasa Con Las Funciones Asincrónicas?
async
las funciones son azúcar sintético para promesas y generadores. Cuando declaras una función async
, sabes que devolverá una promesa. Por eso, también tendrás acceso a todos los métodos de la promesa.
const requests = { user: null, action: null, log(something) { console.log(this); }, async getUser() { this.user = await new Promise(resolve => { setTimeout(() => { resolve("Douglas Pires"); }, 1000); }); this.log("user"); return this; }, async registerAction() { this.action = await new Promise(resolve => { setTimeout(() => { resolve("programming stuff"); }, 1000); }); this.log("action"); return this; }};requests.getUser().then(() => requests.registerAction());
Sin embargo, no es una buena idea encadenar un montón de promesas. Recomiendo usar un montón de palabras clave await
en su lugar. Es más fácil y hará que su código sea mucho más legible.
await requests.getUser(); // Douglas Piresawait requests.registerAction(); // programming
Y tendrá acceso a las mismas propiedades aquí:
console.log(requests.user); // Douglas Piresconsole.log(requests.action); // programming
En conclusión
Las funciones de encadenamiento son útiles cuando se tiene que manipular un objeto. También es una forma práctica de mejorar la legibilidad de tu código. Sin embargo, como has visto anteriormente, debes encadenar sabiamente.
En este artículo, hemos hablado de this
, clases, prototipos y funciones async
en el contexto del encadenamiento de métodos JavaScript. Espero que hayas recogido algunos consejos útiles y que ahora estés mejor informado sobre el tema. Puedes encontrar mi repositorio con todo el código en el encadenamiento de métodos JavaScript aquí mismo. Nos vemos en el próximo post!
¿Te ha gustado leer este artículo? Siéntase libre de compartir en las redes sociales usando los botones a continuación. Alternativamente, también he escrito sobre cómo puedes crear un generador de paletas de colores usando Nuxt y Vuetify. ¡Ve a comprobarlo!