IIFE JavaScript

Le IIFE (Immediately Invoked Function Expressions) sono funzioni JavaScript che vengono eseguite immediatamente dopo essere state definite. Questo pattern è stato fondamentale nello sviluppo JavaScript prima dell’introduzione dei moduli ES6 e rimane utile in molte situazioni per creare scope isolati e prevenire l’inquinamento del namespace globale.
Cos’è una IIFE
Una IIFE è una funzione che viene dichiarata e invocata nello stesso momento. La caratteristica principale è che crea uno scope privato dove le variabili e le funzioni non interferiscono con il codice circostante:
// Sintassi base di una IIFE
(function () {
console.log("Questa funzione viene eseguita immediatamente!");
})();
// Equivale a:
function miaFunzione() {
console.log("Questa funzione viene eseguita immediatamente!");
}
miaFunzione();
// Ma la IIFE non "inquina" il namespace globale con il nome della funzione
Le parentesi attorno alla function declaration sono necessarie per trasformarla in un’espressione, perché JavaScript non permette di invocare direttamente una function declaration.
Sintassi e Varianti
Sintassi Classica
// Variante 1: parentesi attorno a tutto
(function () {
console.log("IIFE variante 1");
})();
// Variante 2: parentesi solo attorno alla funzione
(function () {
console.log("IIFE variante 2");
})();
// Con parametri
(function (nome, età) {
console.log(`Ciao ${nome}, hai ${età} anni`);
})("Mario", 30);
Entrambe le varianti sono valide e funzionalmente identiche. La scelta è spesso questione di preferenza del team o standard di codifica.
Con Arrow Functions
// IIFE con arrow function
(() => {
console.log("Arrow IIFE");
})();
// Con parametri
((nome, età) => {
console.log(`Ciao ${nome}, hai ${età} anni`);
})("Mario", 30);
// IIFE che restituisce un valore
const risultato = (() => {
const a = 5;
const b = 10;
return a + b;
})();
console.log(risultato); // 15
Vantaggi delle IIFE
Incapsulamento e Privacy
Le IIFE creano uno scope privato dove le variabili non sono accessibili dall’esterno:
// Senza IIFE - variabili globali
var contatore = 0;
var incrementa = function () {
contatore++;
return contatore;
};
console.log(contatore); // 0 - accessibile globalmente!
// Con IIFE - incapsulamento
const modelloContatore = (function () {
let contatore = 0; // Privata!
return {
incrementa: function () {
contatore++;
return contatore;
},
ottieni: function () {
return contatore;
},
reset: function () {
contatore = 0;
},
};
})();
console.log(modelloContatore.incrementa()); // 1
console.log(modelloContatore.ottieni()); // 1
// console.log(contatore); // ReferenceError - non accessibile!
Prevenzione Conflitti di Nomi
// Libreria A
(function () {
var utilità = {
formatta: function (testo) {
return testo.toUpperCase();
},
};
window.LibreriaA = utilità;
})();
// Libreria B - può usare lo stesso nome senza conflitti
(function () {
var utilità = {
formatta: function (testo) {
return testo.toLowerCase();
},
};
window.LibreriaB = utilità;
})();
// Uso senza conflitti
console.log(LibreriaA.formatta("ciao")); // "CIAO"
console.log(LibreriaB.formatta("CIAO")); // "ciao"
Pattern Comuni con IIFE
Module Pattern
Prima dei moduli ES6, le IIFE erano il modo principale per creare moduli:
const calcolatore = (function () {
// Variabili private
let memoria = 0;
let storia = [];
// Funzioni private
function registraOperazione(operazione, risultato) {
storia.push({ operazione, risultato, timestamp: Date.now() });
}
// API pubblica
return {
somma: function (a, b) {
const risultato = a + b;
registraOperazione(`${a} + ${b}`, risultato);
return risultato;
},
sottrazione: function (a, b) {
const risultato = a - b;
registraOperazione(`${a} - ${b}`, risultato);
return risultato;
},
memorizza: function (valore) {
memoria = valore;
},
richiama: function () {
return memoria;
},
ottieniStoria: function () {
return [...storia]; // Copia per prevenire modifiche esterne
},
};
})();
// Utilizzo
console.log(calcolatore.somma(5, 3)); // 8
calcolatore.memorizza(10);
console.log(calcolatore.richiama()); // 10
console.log(calcolatore.ottieniStoria()); // Array con operazioni
Namespace Pattern
// Creazione di un namespace globale organizzato
window.MiaApp = (function () {
// Configurazione privata
const config = {
apiUrl: "https://api.esempio.com",
versione: "1.0.0",
};
return {
// Moduli pubblici
utils: {
formatDate: function (date) {
return date.toLocaleDateString("it-IT");
},
validateEmail: function (email) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
},
},
api: {
chiamata: function (endpoint) {
return fetch(config.apiUrl + endpoint);
},
},
getVersion: function () {
return config.versione;
},
};
})();
// Utilizzo
console.log(MiaApp.utils.formatDate(new Date()));
console.log(MiaApp.getVersion());
Inizializzazione Condizionale
// Inizializzazione che dipende da condizioni
(function () {
// Verifica supporto per una feature
if ("geolocation" in navigator) {
console.log("Geolocalizzazione supportata");
// Inizializza servizi di geolocalizzazione
navigator.geolocation.getCurrentPosition(function (position) {
console.log("Posizione ottenuta:", position.coords);
});
} else {
console.log("Geolocalizzazione non supportata");
// Fallback o messaggio utente
}
})();
// Inizializzazione al caricamento DOM
(function () {
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", inizializza);
} else {
inizializza();
}
function inizializza() {
console.log("DOM pronto, inizializzazione completata");
// Logica di inizializzazione
}
})();
IIFE vs Soluzioni Moderne
Prima dei Moduli ES6
// Pattern vecchio con IIFE
const matematica = (function () {
const PI = 3.14159;
function areaCircolo(raggio) {
return PI * raggio * raggio;
}
return {
areaCircolo: areaCircolo,
PI: PI,
};
})();
Con Moduli ES6
// modulo-matematica.js
const PI = 3.14159;
export function areaCircolo(raggio) {
return PI * raggio * raggio;
}
export { PI };
// main.js
import { areaCircolo, PI } from "./modulo-matematica.js";
Quando Usare le IIFE Oggi
Isolamento rapido: Quando hai bisogno di creare rapidamente uno scope isolato senza creare file separati.
Inizializzazione una tantum: Per codice che deve essere eseguito immediatamente e non ha bisogno di essere richiamato.
Compatibilità: In ambienti dove i moduli ES6 non sono disponibili o pratici.
Testing e debugging: Per isolare temporaneamente porzioni di codice durante lo sviluppo.
// Esempio moderno: configurazione rapida
(function () {
// Configurazione specifica per questa pagina
const tema = localStorage.getItem("tema") || "chiaro";
document.body.className = `tema-${tema}`;
// Event listener specifici per questa pagina
document
.getElementById("toggle-tema")
?.addEventListener("click", function () {
const nuovoTema = tema === "chiaro" ? "scuro" : "chiaro";
localStorage.setItem("tema", nuovoTema);
location.reload();
});
})();
Le IIFE rimangono uno strumento utile nel toolkit JavaScript moderno, specialmente per situazioni che richiedono incapsulamento immediato o inizializzazione once-off. Anche se i moduli ES6 hanno sostituito molti dei loro usi tradizionali, comprendere le IIFE è importante per mantenere e comprendere codice legacy e per situazioni specifiche dove offrono la soluzione più semplice.
