Rendi il tuo codice più facile da leggere con la programmazione funzionale

Scopri Functional JavaScript è stato nominato da BookAuthority uno dei migliori nuovi libri di Programmazione funzionale!

Foto di MI PHAM su Unsplash

Le funzioni pure sono più facili da leggere e comprendere. Tutte le dipendenze della funzione sono nella sua definizione e sono quindi più facili da vedere. Anche le funzioni pure tendono ad essere piccole e fanno una cosa. Non usano questo, una costante fonte di confusione.

chaining

Il concatenamento è una tecnica utilizzata per semplificare il codice in cui più metodi vengono applicati uno dopo l'altro a un oggetto.

Guardiamo e confrontiamo i due stili: imperativo e funzionale. Nello stile funzionale, utilizzo la casella degli strumenti di base per filtro operazioni operazioni () e map (). Quindi li incatengo.

Ho preso il caso di una raccolta di compiti. Un'attività ha un id, una descrizione (desc) un booleano completato, un tipo e un oggetto utente assegnato. L'oggetto utente ha una proprietà name.

// Stile imperativo
let filteredTasks = [];
for (let i = 0; i 
// Stile funzionale
funzione isPriorityTask (attività) {
   return task.type === "RE" &&! task.completed;
}
function toTaskView (task) {
   return {... task, userName: task.user.name};
}
let filteredTasks = task.filter (isPriorityTask) .map (toTaskView);

Notare i callback per filter () e map () come pure funzioni con nomi rivelatori intenzionali.

map () trasforma un elenco di valori in un altro elenco di valori utilizzando una funzione di mappatura.

Ecco un test delle prestazioni che misura la differenza tra i due stili. Sembra che l'approccio funzionale sia più lento del 60%. Quando il processo imperativo termina in 10 millisecondi, l'approccio funzionale termina in 16 millisecondi. In tal caso, l'utilizzo dell'anello imperativo sarà un'ottimizzazione prematura.

Stile senza punti

Nell'esempio precedente, ho usato lo stile senza punti durante la composizione di funzioni. Point-free è una tecnica che migliora la leggibilità eliminando gli argomenti non necessari. Considera il codice seguente:

task.filter (task => isPriorityTask (task)). map (task => toTaskView (task));

In uno stile senza punti è scritto senza argomenti:

tasks.filter (isPriorityTask) .map (toTaskView);

Per ulteriori informazioni su come guardare senza punti su Come la composizione senza punti ti renderà un programmatore funzionale migliore

Applicazione parziale

Successivamente, voglio esaminare come possiamo migliorare la leggibilità e anche riutilizzare una funzione esistente. Prima di farlo, abbiamo bisogno di una nuova funzione nella nostra cassetta degli attrezzi.

L'applicazione parziale si riferisce al processo di fissaggio di una serie di argomenti a una funzione.
È un modo per passare dalla generalizzazione alla specializzazione.

Per un'applicazione parziale possiamo usare la funzione partial () di una libreria popolare come underscore.js o lodash.js. Il metodo bind () può anche eseguire un'applicazione parziale.

Diciamo che vogliamo trasformare il seguente codice imperativo in uno stile funzionale, più facile da leggere:

let filteredTasks = [];
for (let i = 0; i 

Come ho detto, questa volta vogliamo creare una funzione generica che può essere utilizzata per filtrare per qualsiasi tipo di attività. isTaskOfType () è la funzione generica. La funzione partial () viene utilizzata per creare una nuova funzione predicato isCreateNewContent () che filtra per un tipo specifico.

Una funzione predicato è una funzione che accetta un valore come input e restituisce vero / falso in base al fatto che il valore soddisfi la condizione.
funzione isTaskOfType (tipo, attività) {
  return task.type === tipo;
}
let isCreateNewContent = partial (isTaskOfType, "NC");
let filteredTasks = task.filter (isCreateNewContent);

Notare la funzione predicato. Ha un nome che esprime la sua intenzione. Quando sto leggendo task.filter (isCreateNewContent) capisco chiaramente quale tipo di attività sto selezionando.

filter () seleziona i valori da un elenco in base a una funzione predicato che decide quali valori devono essere mantenuti.

Ridurre

Inizierò un nuovo esempio usando una lista della spesa. Ecco come potrebbe apparire l'elenco:

lascia shoppingList = [
   {nome: "arancione", unità: 2, prezzo: 10, tipo: "FRT"},
   {nome: "limone", unità: 1, prezzo: 15, tipo: "FRT"},
   {nome: "pesce", unità: 0,5, prezzo: 30, tipo: "MET"}
];

Calcolerò il prezzo totale e il prezzo solo per i frutti. Di seguito è riportato lo stile imperativo:

lascia totalPrice = 0, fruitsPrice = 0;
for (let i = 0; i 

Adottare l'approccio funzionale in questo caso richiederà l'uso di reduce () per calcolare il prezzo totale.

reduce () riduce un elenco di valori a un valore.

Come abbiamo fatto prima, creiamo nuove funzioni per i callback richiesti e diamo loro l'intenzione di rivelare nomi: addPrice () e areFruits ().

funzione addPrice (totalPrice, line) {
   return totalPrice + (line.units * line.price);
}
funzione areFruits (linea) {
   return line.type === "FRT";
}
let totalPrice = shoppingList.reduce (addPrice, 0);
let fruitsPrice = shoppingList.filter (areFruits) .reduce (addPrice, 0);

Conclusione

Le funzioni pure sono più facili da leggere e su cui ragionare.

La programmazione funzionale interromperà le operazioni dell'elenco in passaggi come: filtro, mappa, riduzione, ordinamento. Allo stesso tempo, sarà necessario definire nuove piccole funzioni pure per supportare tali operazioni.

La combinazione della programmazione funzionale con la pratica di dare nomi rivelatori di intenti migliora notevolmente la leggibilità del codice.

Scopri Functional JavaScript è stato nominato da BookAuthority uno dei migliori nuovi libri di Programmazione funzionale!

Per ulteriori informazioni sull'applicazione delle tecniche di programmazione funzionale in React, dai un'occhiata a Functional React.

Maggiori informazioni su Vue e Vuex in Una breve introduzione ai componenti Vue.js.

Scopri come applicare i Principi dei modelli di progettazione.

Puoi trovarmi anche su Twitter.