La sintassi {...} ci consente di creare un oggetto. Ma spesso abbiamo bisogno di creare multipli oggetti simili, come ad esempio pi utenti, oggetti del menu e molto altro.
Questo pu essere fatto utilizzando un costruttore e loperatore "new".
Costruttore
Tecnicamente un costruttore una normale funzione. Ma ci sono due convenzioni:
- Vengono denominati con la prima lettera maiuscola.
- Questi dovrebbero essere eseguiti solo con loperatore
"new".
Ad esempio:
function User(name) {
this.name = name;
this.isAdmin = false;
}
let user = new User("Jack");
alert(user.name); // Jack
alert(user.isAdmin); // false
Quando una funzione viene eseguita con new, esegue questi passaggi:
- Un nuovo oggetto, vuoto, viene creato ed assegnato a
this. - Viene eseguito il corpo della funzione. Solitamente questo modifica
this, aggiungendo nuove propriet. - Viene ritornato il valore assegnato a
this.
In altre parole, new User(...) fa qualcosa del genere:
function User(name) {
// this = {}; (implicito)
// aggiungiamo propriet a this
this.name = name;
this.isAdmin = false;
// return this; (implicito)
}
Quindi let user = new User("Jack") d lo stesso risultato di:
let user = {
name: "Jack",
isAdmin: false
};
Ora, se vogliamo creare altri utenti, possiamo chiamare new User("Ann"), new User("Alice") e cosi via. Molto pi rapido rispetto allutilizzare ogni volta oggetti letterali; risulta anche pi facile da leggere.
Questo il principale scopo dei costruttori implementare codice riutilizzabile per la creazione di oggetti.
Ribadiamo tecnicamente, ogni funzione (eccetto le arrow functions, siccome non hanno this) pu essere utilizzata come costruttore. Ovvero: ogni funzione pu essere eseguita con new. La prima lettera maiuscola semplicemente una convenzione, per rendere esplicito che la funzione deve essere eseguita con new.
Se abbiamo molte linee di codice utili alla creazione di un unico oggetto, possiamo raggrupparle in un costruttore richiamato contestualmente, come qui:
// create a function and immediately call it with new
let user = new function() {
this.name = "John";
this.isAdmin = false;
// ...altro codice per la creazione di user
// magari logiche complesse e istruzioni
// variabili locali etc
};
Il costruttore non pu essere chiamato nuovamente, perch non salvato da nessuna parte; viene solo creato e chiamato. Questo trucco consente di incapsulare un codice che costruisce un singolo oggetto, senza necessit di riutilizzo futuro.
Costruttori modalit test: new.target
La sintassi presentata nella seguente sezione viene utilizzata raramente; potete tranquillamente saltarla se non vi interessa sapere proprio tutto.
Dentro la funzione, possiamo controllare quando questa viene chiamata con new e quando senza, utilizzando una speciale propriet new.target.
Questa risulta undefined per le chiamate normali, mentre contiene la funzione se viene chiamata con new:
function User() {
alert(new.target);
}
// senza "new":
User(); // undefined
// con "new":
new User(); // function User { ... }
Questo pu essere utilizzato per consentire ad entrambe le chiamate di funzionare (con new e senza), quindi sia in in modalit costruttore che in modalit regolare.
Possiamo anche fare in modo che le chiamate con new e quelle regolari facciano la stessa cosa, come in questo esempio:
function User(name) {
if (!new.target) { // se mi esegui senza new
return new User(name); // ...Aggiungo new al posto tuo
}
this.name = name;
}
let john = User("John"); // reindirizza la chiamata a new User
alert(john.name); // John
Questo approccio viene adottato in alcune librerie per rendere la sintassi pi flessibile. Rende possibile la chiamata della funzione sia con new che senza.
Ma non unottima cosa utilizzare la doppia sintassi ovunque, perch omettendo new il codice perde in leggibilit. Con la parola chiave new possiamo sapere con certezza che si sta creando un nuovo oggetto.
Return nel costruttore
Solitamente, i costruttori non hanno listruzione return. Il loro compito di eseguire tutto ci che necessario a creare loggetto lavorando su this; questultimo sar il risultato.
Se decidiamo di inserire unistruzione di return, vanno seguite delle semplici regole:
- Se
returnviene invocato con un oggetto, questo verr ritornato al posto dithis. - Se
returnviene invocato con un tipo primitivo, verr ignorato.
In altre parole, return con un oggetto ritorna quelloggetto; in tutti gli altri casi verr ritornato this.
Ad esempio, qui return sovrascrive this ritornando un oggetto:
function BigUser() {
this.name = "John";
return { name: "Godzilla" }; // <-- ritorna questo oggetto
}
alert( new BigUser().name ); // Godzilla
Qui invece abbiamo un esempio con un return vuoto (potremmo anche ritornare un qualsiasi valore di tipo primitivo):
function SmallUser() {
this.name = "John";
return; // <-- returns this
}
alert(new SmallUser().name); //John
Solitamente i costruttori non hanno listruzione return. Abbiamo comunque riportato, per completezza, quel che succede se si tenta di ritornare un oggetto.
Possiamo anche omettere le parentesi dopo new, se non ci sono argomenti:
let user = new User; // <-- no parentheses
// same as
let user = new User();
Lomissione delle parentesi non viene considerata come buona programmazione, la sintassi comunque lo permette.
Metodi in un costruttore
Utilizzare costruttori per creare degli oggetti ci d un grande vantaggio in termini di flessibilit. Il costruttore pu avere dei parametri che definiscono come costruire loggetto, e cosa metterci dentro.
Ovviamente, possiamo aggiunger a this non solo propriet, ma anche metodi.
Ad esempio, new User(name) crea un oggetto con un nome (passato come name) e un metodo sayHi:
function User(name) {
this.name = name;
this.sayHi = function() {
alert( "My name is: " + this.name );
};
}
let john = new User("John");
john.sayHi(); // My name is: John
/*
john = {
name: "John",
sayHi: function() { ... }
}
*/
Per creare oggetti pi complessi, esiste una sintassi pi avanzata, classes, che copriremo pi avanti.
Riepilogo
- Le funzioni di costruzione, o meglio, i costruttori, sono solo delle normali funzioni; seguono per una convenzione comune che prevede di denominarle con la prima lettera maiuscola.
- Un costruttore dovrebbe essere chiamato solamente utilizzando
new. Questo tipo di chiamata implica la creazione di un oggetto vuoto,this, che verr popolato entro la fine della funzione.
Possiamo utilizzare i costruttori per costruire molti oggetti simili tra loro.
JavaScript fornisce costruttori per la maggior parte degli oggetti integrati nel linguaggio: come Date per le date, Set per gli insiemi e molti altri che studieremo pi avanti.
In questo capitolo abbiamo coperto solamente le basi degli oggetti e dei costruttori. Era necessario conoscerne le basi per capire meglio i data types e le funzioni che studieremo nel prossimo capitolo.
Dopo questo, ritorneremo sugli oggetti e li analizzeremo pi in dettaglio nei capitoli Prototypes, inheritance e Classi.
Commenti
<code>, per molte righe includile nel tag<pre>, per pi di 10 righe utilizza una sandbox (plnkr, jsbin, codepen)