FIRST CLASS FUNCTION

JS

In questo post parleremo di quelle che sono le caratteristiche fondamentali delle funzioni in Javascript. Ti illustrerò concetti molto importanti come l’astrazione, l’incapsulamento che si usava in ES5 chiamato IIFE, la parola chiave this etc.

Definizione
First Class Object

Traducendo questa definizione per quanto riguarda le funzioni JS vuol dire che tutto quello che possiamo fare con stringhe numeri etc. possiamo farlo con le funzioni. Così come possiamo assegnare una variabile ad un numero, una stringa etc. così possiamo assegnare quella variabile a una funzione. Vediamo un esempio di codice per chiarire questi concetti.

Copy to Clipboard

FUNZIONI E ASTRAZIONE

Vediamo cosa si intende per astrazione.

DEFINIZIONE

Astrazione

Degli esempi concreti ci verranno in aiuto.

Copy to Clipboard

IIFE E MODULE PATTERN

IIFE veniva usata in ES5 per implementare un module pattern. Un pattern è un modello che definisce la risoluzione di un determinato problema. Grazie alla IIFE viene creato un contesto riservato al di fuori dello spazio globale. Quindi incapsulando il codice senza possibilità di inquinamento dall’esterno. Analizzare il codice riportato per comprendere questi argomenti.
Copy to Clipboard

CONSTRUCTOR FUNCTION

Gli oggetti in JS possono essere creati in diversi modi. Sintassi letterale, keyword new. Una contructor function è una funzione regolare ma con due convenzioni. La funzione deve iniziare con una lettera maiuscola e deve essere preceduta dalla parola chiave new. In questo caso viene creato un oggetto che eredita proprietà e metodi dal proprio prototype. Cerchiamo di capire dal codice riportato come funziona la creazione di un oggetto con new.
Copy to Clipboard

LA KEYWORD THIS

Le constructor function producono oggetti, definiscono proprietà comuni definite all’interno dell’oggetto prototype, e definiscono altre proprietà con this di cui ogni oggetto avrà la sua copia. Analizziamo il codice per comprendere meglio l’argomento.
Copy to Clipboard

FUNZIONI PURE E IMPURE

funzioni pure e impure
funzione deterministica

Le funzioni pure e impure sono un concetto fondamentale nella programmazione procedurale. Una funzione che prende parametri in input e restituisce sempre lo stesso output è chiamata funzione deterministica.

funzione deterministica
funzione pura

Essendoci il console.log non è ancora una funzione pura in quanto può produrre effetti collaterali nel mondo esterno. Una funzione per essere pura non deve produrre effetti collaterali. console.log mostra a video un’informazione e questo è un effetto collaterale. Una funzione pura semplifica la manutenzione del codice e il debug.

APPROFONDIMENTI

Le funzioni JavaScript sono definite con la parola chiave function. È possibile utilizzare una dichiarazione di funzione o un’espressione di funzione.

DICHIARAZIONE DI FUNZIONE

In precedenza, in questo tutorial, hai appreso che le funzioni sono dichiarate con la seguente sintassi:

function functionName(parameters) {
  // code to be executed
}

Le funzioni dichiarate non vengono eseguite immediatamente. Sono “salvate per un uso successivo” e verranno eseguite in seguito, quando vengono invocate (chiamate).

function myFunction(a, b) {
  return a * b;
}

I punti e virgola vengono utilizzati per separare le istruzioni JavaScript eseguibili. Poiché una dichiarazione di funzione non è un’istruzione eseguibile, non è comune terminarla con un punto e virgola.

ESPRESSIONI DI FUNZIONI

Una funzione JavaScript può anche essere definita utilizzando un’espressione. Un’espressione di funzione può essere memorizzata in una variabile:

const x = function (a, b) {return a * b};

Dopo che un’espressione di funzione è stata memorizzata in una variabile, la variabile può essere utilizzata come una funzione:

const x = function (a, b) {return a * b};
let z = x(4, 3);   //output 12

La funzione sopra è in realtà una funzione anonima (una funzione senza nome). Le funzioni memorizzate nelle variabili non necessitano di nomi di funzioni. Vengono sempre richiamate (chiamate) utilizzando il nome della variabile. La funzione sopra termina con un punto e virgola perché fa parte di un’istruzione eseguibile.

IL COSTRUTTORE FUNCTION()

Come hai visto negli esempi precedenti, le funzioni JavaScript sono definite con la parola chiave function. Le funzioni possono anche essere definite con un costruttore di funzioni JavaScript integrato chiamato Function().

const myFunctionnew Function(“a”, “b”, “return a * b”);

let x = myFunction(4, 3);  //output 12

In realtà non è necessario utilizzare il costruttore di funzioni. L’esempio sopra è lo stesso di scrivere:

const myFunctionfunction (a, b) {return a * b};

let x = myFunction(4, 3);

HOISTING DI FUNZIONI

Il sollevamento (hoisting) è il comportamento predefinito di JavaScript per spostare le dichiarazioni all’inizio dell’ambito corrente. Il sollevamento si applica alle dichiarazioni di variabili e alle dichiarazioni di funzioni. Per questo motivo, le funzioni JavaScript possono essere chiamate prima di essere dichiarate:

myFunction(5);

function myFunction(y) {
  return y * y;
}

FUNZIONI AUTOINVOCANTI

Le espressioni di funzione possono essere “autoinvocate”. Un’espressione che si richiama automaticamente viene invocata (avviata) automaticamente, senza essere chiamata. Le espressioni di funzione verranno eseguite automaticamente se l’espressione è seguita da (). Non è possibile richiamare automaticamente una dichiarazione di funzione. Devi aggiungere parentesi attorno alla funzione per indicare che si tratta di un’espressione di funzione:

(function () {
  let x = “Hello!!”;  // I will invoke myself
})();

LE FUNZIONI POSSONO ESSERE UTILIZZATE COME VALORI

function myFunction(a, b) {
  return a * b;
}

let x = myFunction(4, 3);  // x=12

Le funzioni JavaScript possono essere utilizzate nelle espressioni:

function myFunction(a, b) {
  return a * b;
}
let x = myFunction(4, 3) * 2;  // x=24

LE FUNZIONI SONO OGGETTI

L’operatore typeof in JavaScript restituisce “function” per le funzioni. Tuttavia, le funzioni JavaScript possono essere meglio descritte come oggetti. Le funzioni JavaScript hanno sia proprietà che metodi. La proprietà arguments.length restituisce il numero di argomenti ricevuti quando è stata richiamata la funzione:

function myFunction(a, b) {
  return arguments.length;
}

Il metodo toString() restituisce la funzione come stringa:

function myFunction(a, b) {
  return a * b;
}

let text = myFunction.toString();

//return function myFunction(a, b) { return a * b; }

APPROFONDIMENTO AI

In JavaScript, le funzioni costruttrici, il concetto di prototipo degli oggetti, la parola chiave new, e la keyword this sono concetti fondamentali per la creazione e la gestione degli oggetti. Vediamo ciascuno di questi concetti in dettaglio:

1. Funzione Costruttrice

Una funzione costruttrice è un tipo speciale di funzione che viene utilizzata per creare nuovi oggetti. Quando una funzione viene utilizzata come costruttore, crea un nuovo oggetto e lo imposta come il contesto (this) all’interno della funzione. Le funzioni costruttrici in JavaScript iniziano solitamente con una lettera maiuscola, per convenzione, per differenziarle dalle normali funzioni.

Esempio di funzione costruttrice:

function Persona(nome, cognome) {
     this.nome = nome;
     this.cognome = cognome;
}

const persona1 = new Persona(‘Mario‘, ‘Rossi‘);
console.log(persona1.nome); // Output: Mario

In questo esempio, la funzione Persona agisce come costruttore. Utilizzando la parola chiave new, si crea un nuovo oggetto persona1, con le proprietà nome e cognome.

2. Prototipo degli Oggetti

Ogni oggetto in JavaScript ha una proprietà chiamata prototype che consente di condividere metodi e proprietà tra tutte le istanze create da una funzione costruttrice. Questo meccanismo è parte integrante del modello basato sui prototipi di JavaScript. Gli oggetti creati da una funzione costruttrice possono ereditare le proprietà e i metodi definiti nel prototipo dell’oggetto.

Esempio:

Persona.prototype.saluta = function() {
     console.log(`Ciao, sono ${this.nome} ${this.cognome}`);
};

persona1.saluta(); // Output: Ciao, sono Mario Rossi

In questo esempio, il metodo saluta è stato aggiunto al prototipo della funzione costruttrice Persona. Ora tutte le istanze della funzione costruttrice avranno accesso a questo metodo.

3. La parola chiave new

La parola chiave new viene utilizzata per creare una nuova istanza di un oggetto che utilizza una funzione costruttrice. Quando si utilizza new:

•Viene creato un nuovo oggetto vuoto.

•Il contesto (this) all’interno della funzione costruttrice viene assegnato al nuovo oggetto creato.

•Se la funzione non restituisce esplicitamente un oggetto, il nuovo oggetto creato viene restituito automaticamente.

Esempio:

const persona2 = new Persona(‘Luigi‘, ‘Verdi‘);
console.log(persona2.nome); // Output: Luigi

4. La keyword this

La keyword this in JavaScript si riferisce al contesto in cui una funzione è chiamata. Quando this è utilizzato all’interno di una funzione costruttrice, si riferisce all’oggetto appena creato. Il valore di this può cambiare in base a come viene chiamata la funzione.

Esempio:

function MostraNome() {
    console.log(this.nome);
}

const persona3 = new Persona(‘Franco‘, ‘Bianchi‘);
MostraNome.call(persona3); // Output: Franco

In questo esempio, il metodo call() imposta il contesto di this in MostraNome sull’oggetto persona3, permettendo di accedere alla proprietà nome.

Riepilogo:

Funzione Costruttrice: Una funzione utilizzata per creare nuovi oggetti, che viene invocata con la parola chiave new.

Prototipo degli Oggetti: Un meccanismo che permette di condividere metodi e proprietà tra tutte le istanze di un oggetto.

Parola chiave new: Crea un nuovo oggetto basato su una funzione costruttrice.

Keyword this: Riferisce all’oggetto attuale o al contesto in cui una funzione viene chiamata.

In JavaScript, le funzioni sono considerate cittadini di prima classe (o “first-class citizens”) e possono essere utilizzate come strumenti di astrazione. Questo concetto è fondamentale per comprendere la flessibilità e la potenza del linguaggio JavaScript. Vediamo entrambi i concetti in dettaglio:

Funzioni come Cittadini di Prima Classe (First-Class Citizens)

In molti linguaggi di programmazione, incluse le versioni più moderne di JavaScript, le funzioni sono trattate come oggetti di prima classe. Questo significa che le funzioni possono essere:

1. Assegnate a una variabile,

2. Passate come argomenti a un’altra funzione,

3. Restituite da un’altra funzione,

4. Salvate in strutture dati come array o oggetti,

5. Essere proprietà di un oggetto (metodi).

Essere cittadini di prima classe significa che le funzioni in JavaScript sono trattate come qualsiasi altro valore (come stringhe, numeri, oggetti, ecc.), e possono essere manipolate dinamicamente durante l’esecuzione.

Esempio:

// Assegnazione di una funzione a una variabile
const saluto = function(nome) {
     return `Ciao, ${nome}!`;
};

console.log(saluto(“Marco“)); // Output: Ciao, Marco!

// Passare una funzione come argomento a un’altra funzione
function eseguiFunzione(f) {
     return f(“Sara“);
}

console.log(eseguiFunzione(saluto)); // Output: Ciao, Sara!

In questo esempio, la funzione saluto viene assegnata a una variabile come se fosse un qualsiasi altro valore. Successivamente, viene passata come argomento a un’altra funzione, eseguiFunzione, che la esegue.

Implicazioni del Concetto di Prima Classe

Grazie a questo concetto, le funzioni possono essere utilizzate per costruire potenti astrazioni. Le astrazioni consentono di nascondere i dettagli di implementazione e di concentrarsi su una logica più generale.

1. Funzioni di Callback

Le funzioni di callback sono un esempio comune dell’uso di funzioni come cittadini di prima classe. Una funzione di callback è una funzione passata come argomento a un’altra funzione, che poi la “richiama” (ovvero la esegue) quando è necessario.

Esempio:

function operazione(matematica, a, b) {
        return matematica(a, b);
}

function somma(x, y) {
        return x + y;
}

console.log(operazione(somma, 3, 4)); // Output: 7

In questo esempio, somma è una funzione di callback passata a operazione, che la esegue con i parametri a e b. Questo è un esempio semplice, ma il concetto può essere usato per implementare logiche più complesse come la gestione di eventi o l’uso di funzioni asincrone.

2. Funzioni Anonime e Funzioni Freccia

Un’altra caratteristica di JavaScript è la possibilità di definire funzioni anonime, cioè funzioni senza un nome. Sono molto utili quando si vuole passare una funzione come argomento senza dichiararla esplicitamente.

Esempio:

setTimeout(function() {
console.log(“Eseguiamo questa funzione dopo 2 secondi“);
}, 2000);

Qui, una funzione anonima viene passata come callback a setTimeout, che la eseguirà dopo un certo periodo di tempo.

Le funzioni freccia sono una versione più compatta e moderna delle funzioni anonime:

setTimeout(() => {
console.log(“Eseguiamo questa funzione dopo 2 secondi“);
}, 2000);

Funzioni come Astrazioni

Le funzioni in JavaScript sono strumenti di astrazione, poiché ci permettono di definire un comportamento generico che può essere riutilizzato in diversi contesti. L’astrazione è il processo di nascondere la complessità e di concentrarsi sui concetti fondamentali, consentendo una programmazione più modulare, leggibile e manutenibile.

1. Funzioni di Ordine Superiore (Higher-Order Functions)

Le funzioni di ordine superiore sono funzioni che accettano altre funzioni come argomenti o che restituiscono una funzione come risultato. Questo approccio è potente perché permette di creare soluzioni più astratte e flessibili.

Esempio:

function creaMoltiplicatore(fattore) {
       return function(numero) {
          return numero * fattore;
       };
}

const moltiplicaPerDue = creaMoltiplicatore(2);
console.log(moltiplicaPerDue(5)); // Output: 10

In questo esempio, creaMoltiplicatore è una funzione di ordine superiore che restituisce una nuova funzione. La funzione risultante viene utilizzata per moltiplicare un numero per il fattore fornito come argomento alla funzione principale.

2. Chiusure (Closures)

Le funzioni in JavaScript, grazie al loro comportamento di chiusura (closure), possono ricordare l’ambiente in cui sono state create, consentendo loro di accedere a variabili che non sono più presenti nello scope corrente.

Esempio:

function creaContatore() {
     let contatore = 0;
     return function() {
         contatore++;
         return contatore;
     };
}

const incrementa = creaContatore();
console.log(incrementa()); // Output: 1
console.log(incrementa()); // Output: 2

In questo esempio, la funzione restituita dalla funzione creaContatore “chiude” sul contesto della variabile contatore, permettendole di mantenere il suo valore anche dopo che creaContatore ha terminato l’esecuzione.

Vantaggi delle Astrazioni con le Funzioni

Modularità: Le funzioni astratte permettono di scomporre problemi complessi in componenti più piccoli e gestibili.

Riutilizzabilità: Una funzione astratta può essere riutilizzata in diversi contesti con parametri diversi.

Manutenibilità: La separazione delle preoccupazioni tramite funzioni rende il codice più facile da comprendere e mantenere.

Conclusione

Le funzioni come cittadini di prima classe in JavaScript consentono una flessibilità notevole nella scrittura del codice, permettendo di utilizzarle come qualsiasi altro valore. Questo, insieme alla loro capacità di fungere da astrazioni, permette di scrivere codice più modulare, riutilizzabile e manutenibile. L’uso delle funzioni come callback, funzioni di ordine superiore e chiusure è una parte essenziale di un approccio di programmazione funzionale, ampiamente supportato in JavaScript. In JavaScript, le funzioni possono essere classificate come pure o impure in base al loro comportamento e all’effetto che hanno sullo stato esterno. Ecco una spiegazione di entrambe:

Funzioni Pure:

Una funzione pura è una funzione che:

1. Dipende solo dai propri argomenti: il risultato della funzione dipende esclusivamente dai parametri che riceve, senza fare affidamento su variabili esterne o stati globali.

2. Non ha effetti collaterali: non modifica lo stato esterno alla funzione (ad esempio, non modifica variabili globali, non fa I/O, non muta l’input ricevuto).

3. Deterministica: a parità di input, restituirà sempre lo stesso output.

Esempio di funzione pura:

function somma(a, b) {
      return a + b;
}

In questo caso, la funzione somma è pura perché:

•Dipende solo dai parametri a e b.

•Non modifica variabili esterne.

•Restituirà sempre lo stesso risultato per gli stessi valori di input.

Funzioni Impure:

Una funzione impura è una funzione che:

1. Fa affidamento su stati esterni o variabili globali: il risultato può dipendere da variabili esterne alla funzione o da stati modificabili durante l’esecuzione del programma.

2. Ha effetti collaterali: può modificare variabili esterne, fare operazioni di I/O (come interagire con il DOM o inviare richieste HTTP), o cambiare lo stato globale.

3. Non deterministica: può restituire risultati diversi anche con gli stessi input, se lo stato esterno cambia.

Esempio di funzione impura:

let x = 10;

function sommaImpura(a) {
    return a + x;
}

In questo caso, la funzione sommaImpura è impura perché:

•Il risultato dipende dalla variabile esterna x.

•Se x cambia, la funzione restituirà un risultato diverso anche se a rimane lo stesso.

Perché le funzioni pure sono utili?

Le funzioni pure sono facili da testare, prevedibili e più facili da parallelizzare poiché non dipendono da stati esterni e non hanno effetti collaterali. Le funzioni impure possono essere necessarie in alcune situazioni, come interagire con l’utente o aggiornare il DOM, ma devono essere usate con attenzione.

IL LINGUAGGIO JAVASCRIPT

IL LINGUAGGIO JAVASCRIPT

LINK AL CODICE SU GITHUB

GITHUB