« Back
in javascript es6 functional programming read.
Programación funcional en JavaScript

Programación funcional en JavaScript.

Por qué?

Últimamente en mi trabajo, me he dado cuenta de una tendencia que me preocupa un poco. Se trata de una dependencia excesiva de librerías o frameworks, incluso para hacer tareas sencillas. Sí, estoy hablando de usar JQuery sólo para hacer un $.each() y cosas por el estilo.

Así que este post va dedicado a la programación funcional y a cómo resolver algunos de los problemas más frecuentes utilizando JavaScript nativo, sin librerías, sin tonterías (para ello utilizaré mi característica preferida del ES2015, las arrow functions, simplemente porque el código me parece más legible y más parecido al cálculo lambda).

JavaScript nativo vs UnderscoreJS

He elegido underscore como contraposición por ser la que usamos en mi trabajo actual, pero bien pudiera haber sido lodash. Utilizaremos este array para nuestras operaciones...

var dc = [  
    {name: "batman", power: 100},
    {name: "superman", power: 90},
    {name: "greenarrow", power: 70},
    {name: "greenlantern", power: 70}
];

forEach vs _.each

Esta función no forma parte en sí de la programación funcional estrictamente dicha, pero sí que es una operación de las muchas que se utilizan a diario, con lo que viene al caso el siguiente ejemplo...

// underscore
_.each(dc, x => console.log(x.name));  
// nativo
dc.forEach(x => console.log(x.name));  
// output
// > batman
// > superman
// > greenarrow
// > greenlantern

Aparte de ser nativo, el rendimiento es sustancialmente mejor que el de underscore, y ya no digamos que el de JQuery1.

map vs _.pluck

Una de las operaciones más usadas de underscore, básicamente usada para hacer transformaciones de arrays... para qué inventarían el map()? ;)

// underscore
_.pluck(dc, "name");  
// nativo
dc.map(x => x.name);  
// output
// > ["batman", "superman", "greenarrow", "greenlantern"]

filter vs _.where

Esta función te sonará bastante si alguna vez has hecho SQL, simplemente devuelve los resultados de un array que cumplen con la condición del where, en JavaScript, recibe el nombre de filter.

// underscore
_.where(dc, {power: 70});  
// nativo
dc.filter(x => x.power === 70);  
// output
// > [
// >     Object {name: "greenarrow", power: 70},
// >     Object {name: "greenlantern", power: 70}
// > ]

Además, el filter te da mucho más control ya que puedes meter cualquier clase de condición dentro de la lambda como, por ejemplo, dc.filter(x => x.power > 70), algo que resulta imposible de hacer con el _.where() de underscore.

find vs _.findWhere

Como el where, pero sólo devuelve un resultado: el primero que encuentra.

// undercore
_.findWhere(dc, {power: 90});  
// nativo
dc.find(x => x.power === 90);  
// output
// > Object {name: "superman", power: 90}

Ojo! El find() forma parte del estándar de ES2015, sin embargo, algunos navegadores, como Google Chrome, ya lo implementan.

includes vs _.contains

Estás harto del indexOf(x) > -1? La propuesta del ES2016 es el Array.prototype.includes, me encanta!

// underscore
_.contains([1, 2, 3], 3);  
// nativo
[1, 2, 3].includes(3);
// output
// > true

reduce vs Universe

La función estrella (junto con el map) de la programación funcional! He visto utilizar el reduce para cosas inimaginables, desde convertir una tabla entera de una base de datos a un sólo objeto clave-valor, hasta concatenar un array de 1..n promesas. Aquí utilizaré un ejemplo más sencillo: _.max() & _.min()

// underscore
_.max(dc, "power"); // quién será el héroe más poderoso?  
// nativo
dc.reduce((x,y) => x.power > y.power ? x : y);  
// output
// > Object {name: "batman", power: 100}
// Lo siento Superman, Batman siempre gana!

// underscore
_.min(dc, "power"); // y el más flojo?  
// nativo
dc.reduce((x,y) => x.power < y.power ? x : y);  
// output
// > Object {name: "greenarrow", power: 70}
// Pobre Green Arrow, nadie le quiere...

No voy a negar que en ésta solución en concreto, es mucho más legible la propuesta de underscore, pero simplemente quería que contemplárais el poder del reduce(). He aquí un poco más de magia con el reduce...

Encadenar funciones

La magia de la programación funcional está en el chain de funciones, ya que cada función debe ser atómica y cumplir un sólo propósito, podemos realizar una cadena de funciones para lograr nuestro objetivo en una sóla línea. En underscore esto es un poco ad hoc con la función _.chain(), pero usando JavaScript como Dios manda es realmente intuitivo.

// underscore
_.chain(dc).pluck("name").contains("greenarrow").value();  
// nativo
dc.map(x => x.name).includes("greenarrow");  
// output
// > true

Seguir aprendiendo

Uno nunca deja de aprender y personalmente cada vez que busco en StackOverflow encuentro un uso nuevo del map y el reduce, eso sí, no dejes de acudir a la enciclopedia MDN de Mozilla, hacen un increíble trabajo de documentación para JavaScript y se merecen todos mis respetos.

Espero que este post te haya abierto el apetito y que, a partir de ahora, te lo pienses dos veces antes de escoger el camino fácil, ya que dominar el arte de la programación funcional es lo que te convertirá en un auténtico Ninja del JavaScript! ;)


  1. Para mi sorpresa, en el link anterior sobre el rendimiento de algunas funciones, vi que las propuestas de lodash eran de lejos mucho más rápidas que las implementaciones nativas.

comments powered by Disqus