JavaScript ci permette di modificare la struttura degli oggetti anche dopo la creazione grazie alla sua flessibilità.
Abbiamo già visto come creare un "costruttore" di oggetti; riproponiamo il costruttore di utenti:
function Utente(nome, cognome, email) { this.nome = nome, this.cognome = cognome, this.email = email }
Creato il nostro costruttore possiamo riutilizzarlo per la creazione di diversi utenti:
var marioRossi = new Utente("Mario", "Rossi", "mario.rossi@gmail.com"); var lucaBianchi = new Utente("Luca", "Bianchi", "luca.bianchi@gmail.com");
Sappiamo anche come aggiungere una proprietà o un metodo ad un oggetto:
marioRossi.telefono = "+393303132333"; marioRossi.saluto = function(){ return "Ciao sono " + this.nome + this.cognome + " !"; }
Con la proprietà "prototype" dell'oggetto globale Object, possiamo leggere ,indicare il prototipo di riferimento ed aggiungere proprietà agli stessi prototipi.
Tutti gli oggetti in Javascript hanno un prototipo o più prototipi, come detto, la ricerca di proprietà e metodi risale sino ad identificare quale prototipo la possiede secondo una catena gerarchica ben precisa.
1 | Object |
2 | Oggetti predefiniti |
3 | Costruttori personalizzati |
La ricerca di una proprietà o di un metodo risale la catena dei prototipi fino ad arrivare all’oggetto Object
, il prototipo base di tutti gli oggetti.
var prototipo = marioRossi.prototype; console.log(prototipo); // Restituirà "Utente"
Con prototype possiamo anche aggiungere proprietà a tutte le istanze dei prototipi.
Prototipi sono tutti gli oggetti predefiniti, l'oggetto capostipite Object, e tutti i nostri costruttori di oggetti.
utente.prototype.codiceFiscale; utente.prototype.saluto = function(){ return "Ciao sono " + this.nome + this.cognome + " !"; }
Cosi facendo la proprietà "codiceFiscale" ed il metodo "saluto" saranno aggiunta a tutte le istanze dell'oggetto "Persona".
Nota: Le proprietà viengono aggiunte a tutte le istanze di oggetti generati ma non al costruttore.
Attraverso prototype è possibile aggiungere proprietà e metodi agli oggetti predefiniti in modo da renderli accessibili a tutte le loro istanze.
String.prototype.firma= function(){ return " <br>" + "Pubblicato da cinquepuntozero.it"; } var articolo = new String("Lorem ipsum dolor sit amet, consectetur adipisci elit"); document.write(articolo + articolo.firma());
E' stata implementata nell'oggetto String ed è ereditata dalla istanza "articolo" creata attraverso lo stesso oggetto.
Quindi all'invocazione del metodo firma() la ricerca è risalita sino all'oggetto predefinito/costruttore.
Per effettuare il cambio impostazione del prototipo creiamo un nuovo costrutto "Admin"
function Admin(nome, cognome, email, reparto) { this.nome = nome, this.cognome = cognome, this.email = email, this.reparto = reparto }
Con il metodo .create() dell'oggetto Object possiamo indicare il nuovo prototipo di riferimento
marioRossi.prototype = Object.create(Admin.prototype);
Prototipi sono tutti gli oggetti predefiniti, l'oggetto capostipite Object, e tutti i nostri costruttori di oggetti.
Con il metodo .create() dell'oggetto Object possiamo creare un oggetto indicando preventivamente il prototipo di riferimento.
var articolo = new Object.create(String.prototype);
Questo tipo di sintassi, rispetto alla classica sintassi
var articolo = new String("");
apre a nuove e maggiori possibilità di configurazione delle proprietà degli oggetti.
var articolo = Object.create(null);
var articolo = new Object.create(String.prototype);
var marioRossi = Object.create(Persona.prototype, { nome:{ value: "Mario" }, cognome:{ value: "Rossi" } });
Un descrittore, come il precedente visto "value", è un oggetto che definisce caratteristiche e modalità di accesso alle proprietà di un oggetto.
Di descrittori di proprietà nè esistono due tipi:
Data descriptor | specifica una serie di caratteristiche per le proprietà di un oggetto |
Accessor descriptor | definisce due modalità di accesso per i metodi di un oggetto |
Serie di caratteristiche per le proprietà di un oggetto
writable | Booleano che indica se il valore della proprietà può essere modificato |
configurable | Booleano che indica se il tipo di descrittore può essere modificato e se la proprietà può essere rimossa |
enumerable | Booleano che indica se la proprietà è accessibile durante un ciclo sulle proprietà dell’oggetto |
value | Indica il valore della proprietà |
var marioRossi = Object.create(persona.prototype, { nome: { value : "Mario", writable : false, configurable : false }, cognome: { value : "Rossi", writable : false, configurable : false }, indirizzo: { value : "", writable : true, configurable : true } });
Definisce due modalità di accesso per i metodi di un oggetto
get | comportamento se si invocata un metodo di un oggetto senza passare valori (proprietà in lettura) |
set | comportamento se si invocata un metodo di un oggetto con passaggio di valori (proprietà in scrittura) |
var marioRossi = Object.create(Persona.prototype, { nome: { value : "Mario", writable : false, configurable : false }, saluta: { get: function() { return "Ciao " + this.nome + "!" ; }, set: function(value) { return "Ciao " + this.nome +" da " + value +"!"; }, } } });
L'invocazione di del metodo "saluta()" dell'oggetto "marioRossi" mostrerà differenti risultati a seconda se invocato con o senza paramento.
marioRossi.saluta() // Ciao Mario! marioRossi.saluta("Giovanni"); // Ciao Mario da Giovanni!