Il concetto di getter e setter è abbastanza comune nei linguaggi popolari in uso oggi. Avete mai avuto bisogno di assicurarvi che una data azione sia sempre eseguita prima o dopo aver assegnato un certo valore alla proprietà di un oggetto? Questo è possibile con i setter. Potete anche eseguire qualsiasi tipo di elaborazione quando recuperate il valore di una proprietà usando i getter (ad esempio, la formattazione). Un modo per implementare getter e setter è quello di usare i metodi, come si fa in Java. Tuttavia, da ES5, abbiamo a disposizione un’alternativa molto più elegante e pratica utilizzando la sintassi get
e set
. Bene, cominciamo!
In JavaScript, gli oggetti sono collezioni di proprietà e probabilmente li avete già usati per memorizzare dati. Una proprietà è semplicemente una coppia chiave-valore. Ecco un esempio:
const options = {
timeout: 5000,
retries: 3,
ip: '192.168.1.20',
port: 4001,
};
Le proprietà in un oggetto possono essere facilmente impostate e lette, come questo:
artist.name = 'Carice Anouk van Houten';console.log(artist.name); //=> "Carice Anouk van Houten"
Ancora una volta, questo non è sicuramente niente di nuovo se hai già avuto qualche esperienza con JavaScript. Per fare una distinzione tra queste proprietà regolari e l’altro tipo che vedremo in questo articolo, possiamo chiamare le prime “proprietà dati”.
Getters e setters: il vecchio modo
Prima di ES5, l’unico modo che avevamo per implementare getters e setters era usare metodi regolari. Come nell’esempio qui sotto:
Ho mantenuto la parola chiave function nell’esempio precedente per rendere chiaro che non c’è nessuna magia qui. Solo metodi normali. Avremmo potuto ottenere lo stesso effetto usando la sintassi di definizione del metodo di ES2015, che è più breve e un po’ più elegante:
const config = {
_port: 4001,
setPort(port) {
// ...
},
getPort() {
// ...
},
};
L’uso di questi tipi di getter e setter è abbastanza semplice:
config.setPort(8080);
console.log(config.getPort()); //=> 8080
Incrementare un valore verrebbe fatto così:
item.setQuantity(item.getQuantity() + 1);
Che sembra davvero prolisso se confrontato con l’incremento diretto di una proprietà:
item.quantity += 1;
// Or even simpler...
item.quantity++;
Getters e setters: perché?
Nei linguaggi OO come Java, C++ o C#, è possibile esporre i membri di una classe a diversi livelli utilizzando i modificatori di accesso (come public
, protected
e private
). Questo serve ad implementare un importante concetto di OOP chiamato data hiding.
Un uso molto comune di getter e setter in questi linguaggi è quello di esporre i membri di una classe in modo sicuro. Per esempio, si potrebbe implementare solo un getter per assicurarsi che un membro privato non venga mai cambiato dall’esterno della classe. Un setter, a sua volta, può essere usato per convalidare i valori forniti e preservare l’integrità delle istanze di quella classe.
E in JavaScript?
In JavaScript, le cose sono un po’ diverse. Al momento di scrivere questo articolo, non ci sono modificatori di accesso in JS. Attualmente, la migliore opzione che abbiamo è quella di usare i simboli, che ci danno un certo livello di privacy quando vengono usati come chiavi. Ad alcune persone non piacciono, però. Soprattutto perché è facile rompere questa privacy usando la riflessione.
Non lo considero un vero problema poiché i linguaggi che hanno la riflessione di solito permettono ai programmatori di rompere l’incapsulamento in qualche modo. Il problema che vedo nei simboli è che non sono così pratici da usare come lo sarebbe un semplice accessor privato. La buona notizia è che una proposta EcmaScript che include campi privati è già nella fase 3. E saranno immuni da qualsiasi tipo di riflessione.
Nell’esempio della sezione precedente, non abbiamo usato simboli o qualsiasi altro trucco per simulare un membro privato. La proprietà _port
non ha nulla di speciale di per sé. È solo una normale proprietà di dati e, come tale, può essere impostata o letta direttamente, bypassando completamente il getter e il setter che abbiamo creato.
Siccome spiegare i simboli e altre tecniche di incapsulamento non è lo scopo di questo articolo, non implemento proprietà private nei suoi esempi di codice. Basta tenere a mente che getter e setter sono comunemente (ma non sempre) usati per fornire accesso ai membri incapsulati. Infine, notate il trattino basso che precede il nome della proprietà _port
. È una convenzione de facto tra gli sviluppatori JS, che indica che una data proprietà è privata e non dovrebbe essere accessibile dall’esterno della classe in cui è definita.
Getters e setters: il nuovo modo con le proprietà accessor
Le proprietà accessor sono il modo moderno di definire getters e setters. Quando si tratta della loro definizione, non sono molto diverse dal nostro esempio precedente, ma è il loro uso che è veramente diverso. Per prima cosa, adattiamo il nostro codice per usare le proprietà accessor:
Come potete vedere, solo due cose sono cambiate in questo esempio:
- Invece di avere i metodi
setPort
e getPort
. Usiamo la sintassi set
e get
insieme ad un singolo nome per la proprietà (“port
“, in questo esempio)
- Non abbiamo bisogno della parola chiave
function
qui. Infatti, se provate ad usarla, otterrete un SyntaxError.
Come usare le proprietà accessor?
Se la definizione di una proprietà accessor è abbastanza simile a come creiamo getter e setter della vecchia scuola, il loro uso non ha alcuna differenza visibile da come usiamo le normali proprietà di dati:
config.port = 8080;
console.log(config.port); //=> 8080
E ecco come appare un’espressione di incremento:
timer.seconds += 1;
Sì. È così semplice. =)
Conclusione
- Gli oggetti sono collezioni di proprietà
- Una normale proprietà è solo una coppia chiave-valore e può essere chiamata “proprietà dati”
- Puoi implementare getter e setter come metodi normali. Questo è il modo “vecchia scuola” di farlo in JavaScript.
- Getters e setters sono normalmente usati per fornire accesso ai membri privati di una classe.
- Le proprietà accessorie possono comportarsi esattamente come i vecchi getter e setter basati su metodi regolari, ma il loro uso è progettato per farli sembrare proprietà dati.
Vuoi padroneggiare JavaScript? Ti consiglio vivamente i corsi JavaScript di Mosh.
E se ti è piaciuto questo articolo, condividilo anche con altri!