Vai al contenuto

Funzioni: le basi

Impara a creare e utilizzare funzioni: dichiarazione, parametri, return e scope.

βž• Altri esempi: Approfondimento: funzioni, altri esempi.

Cos'Γ¨ una Funzione?

Una funzione Γ¨ un blocco di codice riutilizzabile che esegue un compito specifico. Invece di scrivere lo stesso codice piΓΉ volte, lo metti in una funzione e la chiami quando serve!

Funzioni nella Vita Reale

Pensa a una funzione come a una ricetta:

  • Ingredienti β†’ Parametri (input)
  • Procedimento β†’ Corpo della funzione (codice)
  • Piatto finale β†’ Valore di ritorno (output)

Una volta creata la "ricetta" (funzione), puoi usarla infinite volte senza riscriverla!

🎯 Vantaggi delle Funzioni

  • βœ… Riutilizzo - Scrivi una volta, usa ovunque
  • βœ… Organizzazione - Codice piΓΉ pulito e leggibile
  • βœ… Manutenzione - Modifica in un solo posto
  • βœ… Testing - PiΓΉ facile testare blocchi isolati
  • βœ… Astrazione - Nascondi la complessitΓ 

Dichiarazione di Funzioni

Ci sono diversi modi per creare funzioni in JavaScript. Vediamo i principali.

  1. Function Declaration (Dichiarazione)

Il modo classico e più comune. ⭐ CONSIGLIATO per iniziare

Dichiarazione Funzione

// Sintassi base
function nomeFunzione() {
    // Codice da eseguire
}

// Esempio pratico
function saluta() {
    console.log("Ciao! πŸ‘‹");
}

// Chiamata (esecuzione) della funzione
saluta();  // Output: "Ciao! πŸ‘‹"

// Puoi chiamarla piΓΉ volte
saluta();  // Output: "Ciao! πŸ‘‹"
saluta();  // Output: "Ciao! πŸ‘‹"
  1. Function Expression (Espressione)

Assegna una funzione a una variabile.

Espressione Funzione

// Funzione anonima assegnata a variabile
const saluta = function() {
    console.log("Ciao! πŸ‘‹");
};

// Chiamata
saluta();  // Output: "Ciao! πŸ‘‹"

// Funzione con nome (opzionale)
const mostraBenvenuto = function benvenuto() {
    console.log("Benvenuto!");
};

mostraBenvenuto();

πŸ“Š Declaration vs Expression

Caratteristica Declaration Expression
Sintassi function nome() {} const nome = function() {}
Hoisting βœ… SΓ¬ (disponibile prima) ❌ No
Quando usare Funzioni globali/principali Callback, funzioni assegnate

πŸ’‘ Hoisting delle Funzioni

Le function declaration sono hoisted (sollevate) all'inizio dello scope, quindi puoi chiamarle prima di dichiararle!

// βœ… Funziona - Declaration
saluta();  // Output: "Ciao!"

function saluta() {
    console.log("Ciao!");
}

// ❌ ERRORE - Expression
// ciao();  // ReferenceError!

const ciao = function() {
    console.log("Ciao!");
};

Parametri e Argomenti

I parametri sono le variabili nella definizione della funzione. Gli argomenti sono i valori passati quando la chiami.

  1. Funzioni con Parametri

Rendono le funzioni piΓΉ flessibili e riutilizzabili.

Parametri Base

// Funzione con un parametro
function saluta(nome) {
    console.log(`Ciao ${nome}! πŸ‘‹`);
}

saluta("Mario");  // Output: "Ciao Mario! πŸ‘‹"
saluta("Anna");   // Output: "Ciao Anna! πŸ‘‹"

// Funzione con piΓΉ parametri
function somma(a, b) {
    console.log(a + b);
}

somma(5, 3);   // Output: 8
somma(10, 20); // Output: 30

// Esempio pratico: Calcolo area rettangolo
function calcolaArea(base, altezza) {
    let area = base * altezza;
    console.log(`Area: ${area} mΒ²`);
}

calcolaArea(5, 10);   // Output: "Area: 50 mΒ²"
calcolaArea(3, 7);    // Output: "Area: 21 mΒ²"
  1. Parametri Predefiniti (Default Parameters)

Valori di default se l'argomento non viene passato (ES6).

Default Parameters

// Senza parametri default
function saluta(nome) {
    console.log(`Ciao ${nome}!`);
}

saluta();  // Output: "Ciao undefined!"

// βœ… Con parametri default
function salutaDefault(nome = "Ospite") {
    console.log(`Ciao ${nome}!`);
}

salutaDefault();         // Output: "Ciao Ospite!"
salutaDefault("Mario");  // Output: "Ciao Mario!"

// Esempio pratico
function calcolaPrezzo(prezzo, sconto = 0) {
    let totale = prezzo - (prezzo * sconto / 100);
    console.log(`Prezzo finale: €${totale}`);
}

calcolaPrezzo(100);      // Output: "Prezzo finale: €100"
calcolaPrezzo(100, 20);  // Output: "Prezzo finale: €80"
  1. Parametri Multipli e Rest Parameter

Gestisci un numero variabile di argomenti con ...rest.

Rest Parameter

// Somma di numeri variabili
function somma(...numeri) {
    let totale = 0;
    for (let numero of numeri) {
        totale += numero;
    }
    return totale;
}

console.log(somma(1, 2, 3));           // 6
console.log(somma(5, 10, 15, 20));     // 50
console.log(somma(100));               // 100

// Combinazione parametri normali + rest
function presentati(nome, etΓ , ...hobbies) {
    console.log(`Mi chiamo ${nome}, ho ${etΓ } anni`);
    console.log(`I miei hobby: ${hobbies.join(", ")}`);
}

presentati("Mario", 30, "calcio", "lettura", "coding");
// Output:
// Mi chiamo Mario, ho 30 anni
// I miei hobby: calcio, lettura, coding

⚠️ Ordine dei Parametri

I parametri con default vanno sempre alla fine, altrimenti saltare argomenti diventa complicato.

// ❌ MALE - Default all'inizio
function male(nome = "Ospite", etΓ ) {
    console.log(`${nome}, ${etΓ } anni`);
}

male(25);  // Output: "25, undefined anni" (confuso!)

// βœ… BENE - Default alla fine
function bene(etΓ , nome = "Ospite") {
    console.log(`${nome}, ${etΓ } anni`);
}

bene(25);  // Output: "Ospite, 25 anni" (chiaro!)

Valore di Ritorno (return)

L'istruzione return restituisce un valore dalla funzione e termina l'esecuzione.

  1. Return Base

Restituisci un valore per usarlo fuori dalla funzione.

Return Statement

// Funzione senza return (restituisce undefined)
function saluta() {
    console.log("Ciao!");
}

let risultato1 = saluta();
console.log(risultato1);  // undefined

// βœ… Funzione con return
function somma(a, b) {
    return a + b;
}

let risultato2 = somma(5, 3);
console.log(risultato2);  // 8

// Puoi usare il valore restituito
let totale = somma(10, 20) + somma(5, 15);
console.log(totale);  // 50
  1. Return Termina la Funzione

Il codice dopo return non viene eseguito.

Return Exit

function controlla(numero) {
    if (numero < 0) {
        return "Negativo";
        console.log("Non eseguito!");  // Mai raggiunto
    }

    if (numero === 0) {
        return "Zero";
    }

    return "Positivo";
}

console.log(controlla(-5));  // "Negativo"
console.log(controlla(0));   // "Zero"
console.log(controlla(10));  // "Positivo"

// Return anticipato per validazione
function dividi(a, b) {
    if (b === 0) {
        return "Errore: divisione per zero";
    }
    return a / b;
}

console.log(dividi(10, 2));  // 5
console.log(dividi(10, 0));  // "Errore: divisione per zero"
  1. Return di Tipi Diversi

Puoi restituire qualsiasi tipo di dato.

Return Vari Tipi

// Return numero
function quadrato(n) {
    return n * n;
}

// Return stringa
function nomeCompleto(nome, cognome) {
    return `${nome} ${cognome}`;
}

// Return boolean
function isPari(numero) {
    return numero % 2 === 0;
}

// Return array
function creaArray(n) {
    let arr = [];
    for (let i = 1; i <= n; i++) {
        arr.push(i);
    }
    return arr;
}

// Return oggetto
function creaUtente(nome, etΓ ) {
    return {
        nome: nome,
        etΓ : etΓ ,
        adulto: etΓ  >= 18
    };
}

// Test
console.log(quadrato(5));                    // 25
console.log(nomeCompleto("Mario", "Rossi")); // "Mario Rossi"
console.log(isPari(4));                      // true
console.log(creaArray(5));                   // [1, 2, 3, 4, 5]
console.log(creaUtente("Anna", 25));
// {nome: "Anna", etΓ : 25, adulto: true}

πŸ’‘ Return vs Console.log

return restituisce un valore utilizzabile, console.log solo mostra a schermo!

// Solo console.log - NON restituisce valore
function somma1(a, b) {
    console.log(a + b);
}

let x = somma1(5, 3);  // Stampa: 8
console.log(x);         // undefined (nessun return!)

// βœ… Con return - RESTITUISCE valore
function somma2(a, b) {
    return a + b;
}

let y = somma2(5, 3);   // Non stampa nulla
console.log(y);         // 8 (valore restituito!)
console.log(y * 2);     // 16 (posso usarlo!)

Scope (Ambito)

Lo scope determina dove le variabili sono accessibili nel codice.

  1. Scope Globale vs Locale

Variabili globali: accessibili ovunque. Locali: solo nella funzione.

Global vs Local Scope

// Variabile GLOBALE
let globale = "Sono globale";

function esempio() {
    // Variabile LOCALE
    let locale = "Sono locale";

    console.log(globale);  // βœ… Accesso OK
    console.log(locale);   // βœ… Accesso OK
}

esempio();

console.log(globale);  // βœ… Accesso OK
// console.log(locale);   // ❌ ERRORE! Non definita fuori

// Esempio pratico
let contatore = 0;  // Globale

function incrementa() {
    let incremento = 1;  // Locale
    contatore += incremento;
}

incrementa();
incrementa();
console.log(contatore);  // 2
// console.log(incremento);  // ❌ ERRORE!
  1. Parametri Come Variabili Locali

I parametri esistono solo dentro la funzione.

Scope Parametri

function saluta(nome) {
    // 'nome' esiste SOLO qui dentro
    console.log(`Ciao ${nome}!`);
}

saluta("Mario");
// console.log(nome);  // ❌ ERRORE! nome non definito

// Shadowing - variabile locale nasconde globale
let numero = 10;  // Globale

function test() {
    let numero = 5;  // Locale (diversa!)
    console.log(numero);  // 5 (locale)
}

test();
console.log(numero);  // 10 (globale invariata)
  1. Block Scope con let e const

let e const hanno scope di blocco (if, for, while...).

Block Scope

function esempio() {
    let x = 1;

    if (true) {
        let x = 2;  // Diversa variabile (block scope)
        console.log(x);  // 2
    }

    console.log(x);  // 1
}

esempio();

// var NON ha block scope (evita var!)
function esempioVar() {
    var y = 1;

    if (true) {
        var y = 2;  // STESSA variabile!
        console.log(y);  // 2
    }

    console.log(y);  // 2 (modificata!)
}

esempioVar();

πŸ“Š Regole dello Scope

Globale

  • Accessibile ovunque
  • Dichiarata fuori funzioni
  • Evita troppi globali!

Funzione

  • Solo dentro la funzione
  • Parametri inclusi
  • Isolamento codice

Blocco

  • Solo nel blocco {}
  • let e const
  • if, for, while

Esempio Completo: Calcolatrice

Sistema Calcolatrice Completo

// Calcolatrice con funzioni
const calcolatrice = {
    // Operazioni base
    somma: function(a, b) {
        return a + b;
    },

    sottrai: function(a, b) {
        return a - b;
    },

    moltiplica: function(a, b) {
        return a * b;
    },

    dividi: function(a, b) {
        if (b === 0) {
            return "Errore: divisione per zero";
        }
        return a / b;
    },

    // Operazioni avanzate
    potenza: function(base, esponente) {
        return Math.pow(base, esponente);
    },

    percentuale: function(numero, percentuale) {
        return (numero * percentuale) / 100;
    },

    media: function(...numeri) {
        if (numeri.length === 0) {
            return 0;
        }
        let somma = 0;
        for (let num of numeri) {
            somma += num;
        }
        return somma / numeri.length;
    }
};

// Funzione helper per formattare risultati
function mostraRisultato(operazione, risultato) {
    console.log(`${operazione} = ${risultato}`);
    console.log("─".repeat(40));
}

// Funzione menu
function eseguiCalcolo(operazione, ...valori) {
    let risultato;

    switch(operazione.toLowerCase()) {
        case "somma":
            risultato = calcolatrice.somma(valori[0], valori[1]);
            mostraRisultato(`${valori[0]} + ${valori[1]}`, risultato);
            break;

        case "sottrai":
            risultato = calcolatrice.sottrai(valori[0], valori[1]);
            mostraRisultato(`${valori[0]} - ${valori[1]}`, risultato);
            break;

        case "moltiplica":
            risultato = calcolatrice.moltiplica(valori[0], valori[1]);
            mostraRisultato(`${valori[0]} Γ— ${valori[1]}`, risultato);
            break;

        case "dividi":
            risultato = calcolatrice.dividi(valori[0], valori[1]);
            mostraRisultato(`${valori[0]} Γ· ${valori[1]}`, risultato);
            break;

        case "potenza":
            risultato = calcolatrice.potenza(valori[0], valori[1]);
            mostraRisultato(`${valori[0]}^${valori[1]}`, risultato);
            break;

        case "percentuale":
            risultato = calcolatrice.percentuale(valori[0], valori[1]);
            mostraRisultato(`${valori[1]}% di ${valori[0]}`, risultato);
            break;

        case "media":
            risultato = calcolatrice.media(...valori);
            mostraRisultato(`Media di ${valori.join(", ")}`, risultato.toFixed(2));
            break;

        default:
            console.log("Operazione non riconosciuta");
            return;
    }

    return risultato;
}

// Test della calcolatrice
console.log("=== CALCOLATRICE ===\n");

eseguiCalcolo("somma", 15, 7);
eseguiCalcolo("sottrai", 20, 8);
eseguiCalcolo("moltiplica", 6, 7);
eseguiCalcolo("dividi", 50, 5);
eseguiCalcolo("potenza", 2, 8);
eseguiCalcolo("percentuale", 200, 15);
eseguiCalcolo("media", 10, 20, 30, 40, 50);

// Output:
// === CALCOLATRICE ===
//
// 15 + 7 = 22
// ────────────────────────────────────────
// 20 - 8 = 12
// ────────────────────────────────────────
// 6 Γ— 7 = 42
// ────────────────────────────────────────
// 50 Γ· 5 = 10
// ────────────────────────────────────────
// 2^8 = 256
// ────────────────────────────────────────
// 15% di 200 = 30
// ────────────────────────────────────────
// Media di 10, 20, 30, 40, 50 = 30.00
// ────────────────────────────────────────

πŸ’‘ Concetti Utilizzati

  • Funzioni come metodi di oggetto
  • Parametri multipli
  • Return per restituire valori
  • Rest parameter (...numeri)
  • Validazione input (divisione per zero)
  • Funzioni helper per formattazione
  • Switch per routing operazioni

Esercizi Pratici

Esercizio 1: Convertitore Temperature

Obiettivo: Crea funzioni per convertire temperature

  • celsiusToFahrenheit(celsius) β†’ Fahrenheit
  • fahrenheitToCelsius(fahrenheit) β†’ Celsius
  • celsiusToKelvin(celsius) β†’ Kelvin
  • Formule: F = (C Γ— 9/5) + 32, K = C + 273.15
Mostra la soluzione

Soluzione Esercizio 1

// Celsius β†’ Fahrenheit
function celsiusToFahrenheit(celsius) {
    return (celsius * 9/5) + 32;
}

// Fahrenheit β†’ Celsius
function fahrenheitToCelsius(fahrenheit) {
    return (fahrenheit - 32) * 5/9;
}

// Celsius β†’ Kelvin
function celsiusToKelvin(celsius) {
    return celsius + 273.15;
}

// Funzione universale
function convertiTemperatura(valore, da, a) {
    // Normalizza a Celsius
    let celsius;

    switch(da.toLowerCase()) {
        case "c":
            celsius = valore;
            break;
        case "f":
            celsius = fahrenheitToCelsius(valore);
            break;
        case "k":
            celsius = valore - 273.15;
            break;
        default:
            return "UnitΓ  non valida";
    }

    // Converti a unitΓ  richiesta
    switch(a.toLowerCase()) {
        case "c":
            return celsius;
        case "f":
            return celsiusToFahrenheit(celsius);
        case "k":
            return celsiusToKelvin(celsius);
        default:
            return "UnitΓ  non valida";
    }
}

// Test
console.log("=== CONVERTITORE TEMPERATURE ===");
console.log(`0Β°C = ${celsiusToFahrenheit(0)}Β°F`);
console.log(`32Β°F = ${fahrenheitToCelsius(32)}Β°C`);
console.log(`0Β°C = ${celsiusToKelvin(0)}K`);
console.log("\nConversioni multiple:");
console.log(`100Β°C β†’ ${convertiTemperatura(100, "C", "F")}Β°F`);
console.log(`100Β°C β†’ ${convertiTemperatura(100, "C", "K")}K`);

// Output:
// === CONVERTITORE TEMPERATURE ===
// 0Β°C = 32Β°F
// 32Β°F = 0Β°C
// 0Β°C = 273.15K
//
// Conversioni multiple:
// 100Β°C β†’ 212Β°F
// 100Β°C β†’ 373.15K

Esercizio 2: Validatore Password

Obiettivo: Crea una funzione che valida password

  • Lunghezza minima 8 caratteri
  • Almeno una lettera maiuscola
  • Almeno una lettera minuscola
  • Almeno un numero
  • Return oggetto con {valida: bool, errori: array}
Mostra la soluzione

Soluzione Esercizio 2

function validaPassword(password) {
    let errori = [];

    // Controllo lunghezza
    if (password.length < 8) {
        errori.push("Deve contenere almeno 8 caratteri");
    }

    // Controllo maiuscola
    if (!/[A-Z]/.test(password)) {
        errori.push("Deve contenere almeno una lettera maiuscola");
    }

    // Controllo minuscola
    if (!/[a-z]/.test(password)) {
        errori.push("Deve contenere almeno una lettera minuscola");
    }

    // Controllo numero
    if (!/[0-9]/.test(password)) {
        errori.push("Deve contenere almeno un numero");
    }

    return {
        valida: errori.length === 0,
        errori: errori
    };
}

// Funzione per mostrare risultato
function mostraValidazione(password) {
    console.log(`\nPassword: "${password}"`);
    let risultato = validaPassword(password);

    if (risultato.valida) {
        console.log("βœ… Password valida!");
    } else {
        console.log("❌ Password non valida:");
        risultato.errori.forEach((errore, i) => {
            console.log(`  ${i + 1}. ${errore}`);
        });
    }
}

// Test
console.log("=== VALIDATORE PASSWORD ===");

mostraValidazione("abc");
mostraValidazione("abcdefgh");
mostraValidazione("Abcdefgh");
mostraValidazione("Abcdefgh123");

// Output:
// === VALIDATORE PASSWORD ===
//
// Password: "abc"
// ❌ Password non valida:
//   1. Deve contenere almeno 8 caratteri
//   2. Deve contenere almeno una lettera maiuscola
//   3. Deve contenere almeno un numero
//
// Password: "abcdefgh"
// ❌ Password non valida:
//   1. Deve contenere almeno una lettera maiuscola
//   2. Deve contenere almeno un numero
//
// Password: "Abcdefgh"
// ❌ Password non valida:
//   1. Deve contenere almeno un numero
//
// Password: "Abcdefgh123"
// βœ… Password valida!

Esercizio 3: Generatore Numeri Casuali

Obiettivo: Crea funzioni per numeri random

  • random(min, max) β†’ numero casuale tra min e max
  • randomArray(n, min, max) β†’ array di n numeri casuali
  • lanciaDado() β†’ numero 1-6
  • lanciaDadi(n) β†’ somma di n dadi
Mostra la soluzione

Soluzione Esercizio 3

// Numero casuale tra min e max (inclusi)
function random(min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

// Array di numeri casuali
function randomArray(n, min, max) {
    let arr = [];
    for (let i = 0; i < n; i++) {
        arr.push(random(min, max));
    }
    return arr;
}

// Lancia un dado (1-6)
function lanciaDado() {
    return random(1, 6);
}

// Lancia n dadi e restituisce somma
function lanciaDadi(n = 2) {
    let somma = 0;
    let dadi = [];

    for (let i = 0; i < n; i++) {
        let dado = lanciaDado();
        dadi.push(dado);
        somma += dado;
    }

    return {
        dadi: dadi,
        somma: somma
    };
}

// Simulazione lancio moneta
function lanciaMone() {
    return random(0, 1) === 0 ? "Testa" : "Croce";
}

// Test
console.log("=== GENERATORE NUMERI CASUALI ===\n");

console.log("Numero casuale (1-100):", random(1, 100));
console.log("Array 5 numeri (1-10):", randomArray(5, 1, 10));
console.log("Lancio dado:", lanciaDado());

let risultato = lanciaDadi(3);
console.log(`\nLancio 3 dadi: ${risultato.dadi.join(" + ")}`);
console.log(`Somma: ${risultato.somma}`);

console.log("\nLancio moneta:");
for (let i = 0; i < 5; i++) {
    console.log(`  Lancio ${i + 1}: ${lanciaMone()}`);
}

// Output (esempio, varia):
// === GENERATORE NUMERI CASUALI ===
//
// Numero casuale (1-100): 47
// Array 5 numeri (1-10): [3, 8, 2, 9, 5]
// Lancio dado: 4
//
// Lancio 3 dadi: 5 + 2 + 6
// Somma: 13
//
// Lancio moneta:
//   Lancio 1: Testa
//   Lancio 2: Croce
//   Lancio 3: Croce
//   Lancio 4: Testa
//   Lancio 5: Testa

🎯 Riepilogo Lezione

Dichiarazione:

  • function nome() {}
  • Hoisting βœ…
  • Uso generale

Parametri:

  • Input funzione
  • Default values
  • Rest parameter

Return:

  • Output funzione
  • Termina esecuzione
  • Qualsiasi tipo

Scope:

  • Globale
  • Funzione
  • Blocco (let/const)