Jack Franklin

December 23, 2013

Per la maggior parte, in JavaScript, quello che vedi è quello che ottieni. Un valore è un valore; non ci sono trucchi. A volte, però, vuoi un valore che si basa su altri valori: il nome completo di qualcuno, per esempio, è una concatenazione del suo nome e cognome. Se avete un oggetto person, e volete che gli utenti di quell’oggetto siano in grado di impostare il nome completo, il nome o il cognome, e vedere il cambiamento immediatamente riflesso negli altri valori, lo costruite convenzionalmente con le funzioni:

person.setLastName('Smith');person.setFirstName('Jimmy');person.getFullName(); // Jimmy Smith

Ma questo è brutto, e richiede che agli utenti del vostro oggetto importi che le proprietà siano correlate; in un esempio più complesso, questo potrebbe non essere così ovvio come con i nomi. Fortunatamente, c’è un modo migliore, aggiunto in ECMAScript 5.

Incontra i getter e i setter.

Come

Facciamo l’oggetto persona. Vogliamo essere in grado di impostare il nome, il cognome o il nome completo, e fargli aggiornare gli altri due automaticamente.

var person = { firstName: 'Jimmy', lastName: 'Smith', get fullName() { return this.firstName + ' ' + this.lastName; }, set fullName (name) { var words = name.toString().split(' '); this.firstName = words || ''; this.lastName = words || ''; }}

person.fullName = 'Jack Franklin';console.log(person.firstName); // Jackconsole.log(person.lastName) // Franklin

Quindi cosa sta succedendo qui?

Le parole chiave get e set sono importanti. Seguono la proprietà a cui si riferiscono (fullName) e un corpo di funzione che definisce il comportamento quando si accede alla proprietà (name = person.fullName) o la si modifica (person.fullName = 'Some Name').

Queste due parole chiave definiscono funzioni accessorie: un getter e un setter per la proprietà fullName. Quando si accede alla proprietà, viene utilizzato il valore di ritorno del getter. Quando viene impostato un valore, il setter viene chiamato e gli viene passato il valore che è stato impostato. Sta a te decidere cosa fare con quel valore, ma ciò che viene restituito dal setter è il valore che è stato passato – quindi non hai bisogno di restituire nulla.

Il modo ufficiale: Object.defineProperty

Oltre al metodo inline per dichiarare getter e setter, può anche essere fatto più esplicitamente tramite Object.defineProperty (MDN Documentation). Questo metodo prende tre argomenti. Il primo è l’oggetto a cui aggiungere la proprietà, il secondo è il nome della proprietà e il terzo è un oggetto che descrive la proprietà (noto come descrittore della proprietà). Ecco un esempio che replica l’esempio precedente:

var person = { firstName: 'Jimmy', lastName: 'Smith'};

Object.defineProperty(person, 'fullName', {get: function() {return firstName + ' ' + lastName;},set: function(name) {var words = name.split(' ');this.firstName = words || '';this.lastName = words || '';}});

Il vantaggio qui non è immediatamente evidente. Oltre a poter aggiungere proprietà dopo aver creato l’oggetto iniziale, c’è un reale beneficio?

Quando si definisce una proprietà in questo modo, si può fare molto di più che definire un setter o un getter. Puoi anche passare le seguenti chiavi:

  • configurable (false di default): se questo è vero, la configurazione della proprietà sarà modificabile in futuro.
  • enumerable (false di default): se è vero, la proprietà apparirà quando si fa il looping sull’oggetto (for (var key in obj)).

Possiamo anche definire proprietà che non hanno getter o setter espliciti:

Object.defineProperty(person, 'age', { value: 42});

Questo creerà person.age, e lo imposterà al valore 42. È importante notare che questa proprietà non è scrivibile. Chiamare person.age = 99 non avrà alcun effetto. In questo modo potete creare proprietà di sola lettura. Se una proprietà ha una chiave value impostata, non può avere un getter o un setter. Le proprietà possono avere valori o accessi, non entrambi.

Non solo, ma poiché la proprietà enumerable è di default a false, questa proprietà non apparirà quando faremo un loop sulle chiavi dell’oggetto.

Se volessimo rendere una proprietà scrivibile, dovremmo impostare la proprietà writable:

Object.defineProperty(person, 'age', { value: 42, writable: true});

Ora, person.age = 99; avrà l’effetto desiderato.

Overuse

Ricorda: solo perché una funzione esiste, non deve essere usata sempre. Getters e Setters hanno i loro casi d’uso, ma non esagerate, o molto probabilmente vi ritroverete con un design che confonde chi interagisce con i vostri oggetti. Usati con attenzione, sono molto potenti. Ma da un grande potere derivano grandi responsabilità.

Supporto browser?

IE9 e superiori hanno pieno supporto per Object.defineProperty, insieme a Safari 5+, Firefox 4+, Chrome 5+ e Opera 12+. Se stai lavorando con Node.js, c’è pieno supporto. Non amate Node?!

Questo articolo è stato scritto insieme a Tom Ashworth. Grazie a Tom per tutto il suo aiuto nel metterlo insieme.

Se ti è piaciuto questo post, iscriviti alla newsletter per essere aggiornato sui nuovi contenuti 😎.

Tutti i post del blog

Se ti è piaciuto questo post, assicurati di seguirmi su Twitter.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.