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 unespressione di funzione per creare una funzione ed assegnarla alla propriet user.sayHi delloggetto.
Successivamente possiamo chiamarla. Ora lutente pu parlare!
Una funzione che una propriet di un oggetto si chiama metodo.
Quindi, nellesempio abbiamo un metodo sayHi delloggetto 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 larchitettura 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 allereditariet 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 nelloggetto.
Ad esempio, il codice dentro user.sayHi() potrebbe aver bisogno del nome delluser.
Per accedere alloggetto, un metodo pu utilizzare la parola chiave this.
Il valore di this loggetto 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 alloggetto 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 unaltra variabile, ad esempio admin = user e sovrascrivere user con qualcosaltro, verrebbe allora effettuato laccesso alloggetto 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
Se scriviamo this.name piuttosto di user.name allinterno di alert, il codice funzioner.
this non ha limiti
In JavaScript, la parola chiave this si comporta diversamente da come fa in molti altri linguaggi di programmazione. Essa pu essere usata in qualsiasi funzione, anche se non si tratta del metodo di un oggetto.
Non c alcun errore di sintassi in un codice come questo:
function sayHi() {
alert( this.name );
}
Il valore di this viene valutato al momento dellesecuzione. E pu essere un valore qualsiasi.
Ad esempio, la stessa funzione potrebbe avere diversi this quando viene chiamata da oggetti diversi:
let user = { name: "John" };
let admin = { name: "Admin" };
function sayHi() {
alert( this.name );
}
// utilizziamo la stessa funzione su due oggetti
user.f = sayHi;
admin.f = sayHi;
// queste chiamate hanno un this diverso
// "this" all'interno della funzione riferito all'oggetto "prima del punto"
user.f(); // John (this == user)
admin.f(); // Admin (this == admin)
admin['f'](); // Admin (il punto o le parentesi quadre forniscono entrambi accesso ai metodi - non c' differenza)
La regola semplice: se viene chiamato obj.f(), allora, durante la chiamata di f, this si riferisce a obj. Nellesempio sopra assume il valore sia di user che di admin.
this == undefinedPossiamo anche chiamare la funzione senza un oggetto:
function sayHi() {
alert(this);
}
sayHi(); // undefined
In questo caso this undefined in modalit strict. Se tentiamo di accedere a this.name, ci sar un errore.
Se non attiva la modalit strict il valore di this in questo caso sar loggetto globale (window in un browser, lo studieremo pi avanti nel capitolo Oggetto globale). Questo strano comportamento ha delle motivazioni storiche, che "use strict" risolve.
Solitamente questo tipo di chiamate significano un errore di programmazione. Se c un this allinterno di una funzione, ci si aspetta che sia chiamato da un oggetto.
thisSe avete utilizzato altri linguaggi di programmazione, probabilmente sarete abituati allidea di un this limitato: quando viene definito un metodo in un oggetto, questo avr sempre in this il riferimento alloggetto.
In JavaScript this libero, il suo valore viene calcolato durante lesecuzione e non dipende da dove il metodo stato definito, ma piuttosto dalloggetto prima del punto.
Il concetto di valutare this durante lesecuzione ha i suoi pregi e difetti. Da una parte una funzione pu essere riutilizzata per oggetti diversi, dallaltra questa grande flessibilit pu essere fonte di molti errori.
Il nostro scopo non di giudicare se questa caratteristica del linguaggio sia buona o cattiva, ma di capire come lavorare con essa sfruttandone i benefici ed evitando i problemi.
Le arrow functions non hanno this
Ad esempio, qui arrow() usa this preso dal metodo esterno user.sayHi():
let user = {
firstName: "Ilya",
sayHi() {
let arrow = () => alert(this.firstName);
arrow();
}
};
user.sayHi(); // Ilya
Questa una speciale caratteristica delle arrow functions; utile quando non vogliamo avere un ulteriore this, ma utilizzare quello del contesto esterno. Pi avanti nel capitolo Arrow functions rivisitate studieremo pi in dettaglio le arrow functions.
Riepilogo
- Le funzioni che vengono memorizzate come propriet di un oggetto vengono dette metodi.
- I metodi consentono agli oggetti di agire, come
object.doSomething(). - I metodi possono riferirsi alloggetto tramite
this.
Il valore this viene definito durante lesecuzione (run-time).
- Quando una funzione viene dichiarata, pu utilizzare
this, ma questothisnon avr alcun valore fino a che la funzione non verr chiamata. - Una funzione pu essere copiata in vari oggetti.
- Quando una funzione viene chiamata come metodo:
object.method(), il valore dithisdurante la chiamata si riferisce aobject.
Da notare che le arrow functions sono speciali: non hanno this. Quando si prova ad accedere a this in una funzione freccia, questo verr preso dal contesto esterno.
Commenti
<code>, per molte righe includile nel tag<pre>, per pi di 10 righe utilizza una sandbox (plnkr, jsbin, codepen)