Gli oggetti solitamente vengono creati per rappresentare entità del mondo reale, come utenti, prodotti e molto altro:
let user = {
name: "John",
age: 30
};
Inoltre, nel mondo reale, un utente può agire: selezionare qualcosa dalla lista degli acquisti, effettuare login, logout etc.
In JavaScript le azioni vengono rappresentate tramite le funzioni.
Esempio di un metodo
Per iniziare, insegniamo a user a salutare:
let user = {
name: "John",
age: 30
};
user.sayHi = function() {
alert("Hello!");
};
user.sayHi(); // Hello!
Qui abbiamo appena utilizzato un’espressione di funzione per creare una funzione ed assegnarla alla proprietà user.sayHi dell’oggetto.
Successivamente possiamo chiamarla. Ora l’utente può parlare!
Una funzione che è una proprietà di un oggetto si chiama metodo.
Quindi, nell’esempio abbiamo un metodo sayHi dell’oggetto user.
Ovviamente possiamo utilizzare una funzione già dichiarata come metodo:
let user = {
// ...
};
// prima la dichiariamo
function sayHi() {
alert("Hello!");
};
// poi la aggiungiamo come metodo
user.sayHi = sayHi;
user.sayHi(); // Hello!
Quando scriviamo codice utilizzando gli oggetti per rappresentare le entità, questa viene definita programmazione orientata agli oggetti, in breve: “OOP”.
OOP è una grande cosa, un ambito di interesse con i propri studi. Come scegliere le giuste entità? Come organizzare le interazioni tra loro? Questa è l’architettura di un codice, e ci sono molti libri importanti che trattano questo argomento, come “Design Patterns: Elements of Reusable Object-Oriented Software” di E.Gamma, R.Helm, R.Johnson, J.Vissides oppure “Object-Oriented Analysis and Design with Applications” di G.Booch, e molti altri.
La forma breve dei metodi
Esiste una sintassi più breve per i metodi in un oggetto letterale:
// questi oggetti fanno la stessa cosa
user = {
sayHi: function() {
alert("Hello");
}
};
// la sintassi più breve risulta più carina
user = {
sayHi() { // equivalente a "sayHi: function(){...}"
alert("Hello");
}
};
Come possiamo notare, si può omettere "function" e scrivere solamente sayHi().
A dire la verità, la notazione non è proprio uguale. Ci sono delle sottili differenze legate all’ereditarietà degli oggetti (le studieremo più avanti), ma per ora non hanno importanza. Nella maggior parte dei casi la forma breve viene preferita.
“this” nei metodi
E’ molto comune che, per eseguire determinate azioni, un metodo abbia necessità di accedere alle informazioni memorizzate nell’oggetto.
Ad esempio, il codice dentro user.sayHi() potrebbe aver bisogno del nome dell’user.
Per accedere all’oggetto, un metodo può utilizzare la parola chiave this.
Il valore di this è l’oggetto “prima del punto”, quello che ha eseguito la chiamata del metodo.
Ad esempio:
let user = {
name: "John",
age: 30,
sayHi() {
// "this" is the "current object"
alert(this.name);
}
};
user.sayHi(); // John
In fase di esecuzione, quando viene chiamato il metodo user.sayHi(), il valore di this sarà user.
Tecnicamente, è possibile accedere all’oggetto anche senza this; lo si fa tramite riferimento alla variabile esterna:
let user = {
name: "John",
age: 30,
sayHi() {
alert(user.name); // "user" piuttosto di "this"
}
};
…Questo codice è instabile. Se decidessimo di copiare user in un’altra variabile, ad esempio admin = user e sovrascrivere user con qualcos’altro, verrebbe allora effettuato l’accesso all’oggetto sbagliato.
Dimostriamolo:
let user = {
name: "John",
age: 30,
sayHi() {
alert( user.name ); // porta ad un errore
}
};
let admin = user;
user = null; // sovrascriviamo per rendere tutto più ovvio
admin.sayHi(); // Errore: non possiamo leggere la proprietà 'name' di null