JavaScript Proxy: semplificare gestione e manutenzione del codice

  



JavaScript è un linguaggio estremamente potente e versatile, ma come tutti i linguaggi di programmazione, può essere soggetto a sfide in termini di manutenibilità e leggibilità del codice. Una delle funzionalità più interessanti introdotte nelle versioni più recenti di JavaScript è il Proxy

Questo strumento permette di creare oggetti "proxy", che agiscono come intermediari tra l'operazione effettuata su un oggetto e l'oggetto stesso. In sostanza, un proxy è un oggetto che può "intercettare" e personalizzare operazioni su un altro oggetto, come lettura, scrittura, chiamate di funzione, e altro.

In questo articolo esploreremo i principali vantaggi dell'uso di Proxy e come può semplificare il codice, migliorando la sua manutenibilità. Mostreremo anche un esempio concreto per evidenziare come il Proxy possa semplificare operazioni che altrimenti richiederebbero molteplici linee di codice.

🔗 Ti piace Techelopment? Dai un’occhiata al sito per tutti i dettagli!


Cos'è un Proxy in JavaScript?

Un Proxy in JavaScript è un oggetto che consente di definire comportamenti personalizzati per operazioni fondamentali, come la lettura e la scrittura di proprietà, la chiamata di funzioni, e la gestione di metodi get, set, apply, construct, ecc. Un proxy è creato utilizzando il costruttore Proxy, che richiede due argomenti:

  1. target: l'oggetto che si vuole "proxyizzare".

  2. handler: un oggetto che definisce i metodi da invocare in risposta alle operazioni su quel target.

Ecco la sintassi di base per creare un proxy:


const handler = {
    get: function(target, prop, receiver) {
        // Logic to intercept access to properties
    },
    set: function(target, prop, value, receiver) {
        // Logic to intercept the assignment of values
    }
};

const proxy = new Proxy(targetObject, handler);


Vantaggi principali di usare JavaScript Proxy

1. Intercettare e personalizzare le operazioni sugli oggetti

Con un Proxy, puoi facilmente intercettare le operazioni sugli oggetti, come lettura, scrittura e invocazione di metodi. Questo ti permette di personalizzare il comportamento del codice senza modificare direttamente gli oggetti target.

Esempio di intercettazione di un accesso a proprietà:


const user = {
    name: 'John',
    age: 30
};

const handler = {
    get(target, prop) {
        if (prop === 'name') {
        return `Hello, ${target[prop]}!`;
        }
        return prop in target ? target[prop] : 'Property not found';
    }
};

const proxy = new Proxy(user, handler);
console.log(proxy.name); // "Hello, John!"
console.log(proxy.age);  // 30
console.log(proxy.email); // "Property not found"

In questo caso, possiamo intercettare la lettura della proprietà name e aggiungere una logica personalizzata, senza modificare l'oggetto user originale.

2. Validazione dei dati in modo centralizzato

Un altro vantaggio significativo dell'uso del Proxy è che puoi implementare una logica di validazione centralizzata quando si assegnano valori alle proprietà dell'oggetto. Invece di dover scrivere un codice di validazione per ogni proprietà, puoi centralizzarlo nel handler del Proxy.

Esempio di validazione delle proprietà prima di assegnare un valore:


const user = {
    name: '',
    age: 0
};

const handler = {
    set(target, prop, value) {
    if (prop === 'age' && (value < 0 || value > 120)) {
        console.error('Invalid age!');
        return false;
    }
    target[prop] = value;
    return true;
    }
};

const proxy = new Proxy(user, handler);
proxy.age = 25;  // It works
proxy.age = -5;  // Invalid age!

In questo esempio, la validazione dell'età viene gestita direttamente nel Proxy, centralizzando la logica e riducendo il rischio di errori sparsi nel codice.

3. Monitoraggio e logging delle operazioni

Un Proxy può essere utilizzato anche per monitorare e fare il log delle operazioni sugli oggetti, come lettura e scrittura. Questo è utile, ad esempio, in situazioni in cui vuoi tracciare le modifiche a un oggetto per motivi di debugging o auditing.

Esempio di log delle operazioni:


const data = {
    name: 'Alice',
    balance: 1000
};

const handler = {
    get(target, prop) {
        console.log(`Getting ${prop}`);
        return prop in target ? target[prop] : undefined;
    },
    set(target, prop, value) {
        console.log(`Setting ${prop} to ${value}`);
        target[prop] = value;
    }
};

const proxy = new Proxy(data, handler);
console.log(proxy.name);   // Getting name
proxy.balance = 2000;      // Setting balance to 2000


Esempio pratico: Oggetto config con Default e Validazione

Immagina di avere un oggetto config che contiene le impostazioni di un'applicazione. Senza Proxy, dovresti controllare manualmente se una proprietà esiste, assegnare valori predefiniti e validare i dati ogni volta che li modifichi.

Vediamo prima come si farebbe senza Proxy e poi come il Proxy semplifica tutto.

🚫 Senza Proxy: codice verboso e ripetitivo


const config = {
    theme: "light",
    language: "en",
    fontSize: 14
};

function getConfig(prop) {
    return config[prop] !== undefined ? config[prop] : "⚠ Default value";
}

function setConfig(prop, value) {
    if (prop === "fontSize" && (typeof value !== "number" || value < 10 || value > 30)) {
        console.error("❌ Invalid fontSize! Must be between 10 and 30.");
        return;
    }
    config[prop] = value;
}

// Usage
console.log(getConfig("theme")); // "light"
console.log(getConfig("unknown")); // "⚠ Default value"

setConfig("fontSize", 50); // ❌ Error
setConfig("fontSize", 20); // ✅ It works
console.log(getConfig("fontSize")); // 20

Problemi:

  • Devi sempre controllare se una proprietà esiste (getConfig).

  • Devi validare manualmente i dati (setConfig).

  • Se hai molte proprietà, il codice diventa difficile da mantenere.


Con Proxy: più semplice e manutenibile


const defaultConfig = {
    theme: "light",
    language: "en",
    fontSize: 14
};

const handler = {
    get(target, prop) {
        return prop in target ? target[prop] : "⚠ Default value";
    },
    set(target, prop, value) {
        if (prop === "fontSize" && (typeof value !== "number" || value < 10 || value > 30)) {
            console.error("❌ Invalid fontSize! Must be between 10 and 30.");
            return false;
        }
        target[prop] = value;
        return true;
    }
};

const config = new Proxy(defaultConfig, handler);

// Usage
console.log(config.theme); // "light"
console.log(config.unknown); // "⚠ Default value"

config.fontSize = 50; // ❌ Error
config.fontSize = 20; // ✅ It works
console.log(config.fontSize); // 20

🎯 Perché il Proxy è meglio?

Niente più controlli manuali: Se una proprietà non esiste, restituisce automaticamente un valore predefinito.
Validazione centralizzata: Se un valore è errato, il Proxy lo intercetta e impedisce l'assegnazione.
Codice più pulito e riutilizzabile.


Conclusioni

JavaScript Proxy è uno strumento potente che può semplificare molte operazioni complesse e rendere il codice più manutenibile e leggibile. Consente di intercettare operazioni sugli oggetti, centralizzare logiche come la validazione, il logging e il calcolo, migliorando notevolmente la manutenibilità del codice a lungo termine. Con esempi concreti come la gestione di un carrello, è facile vedere come il Proxy possa semplificare la scrittura di codice più robusto e facile da mantenere.

Utilizzare i Proxy in modo strategico può essere una risorsa fondamentale per migliorare la qualità del codice in progetti complessi.

 

Follow me #techelopment

Official site: www.techelopment.it
facebook: Techelopment
instagram: @techelopment
X: techelopment
Bluesky: @techelopment
telegram: @techelopment_channel
whatsapp: Techelopment
youtube: @techelopment