39 OOP
Il paradigma dell’ Object Oriented Programming nasce come risposta alla sempre più crescente complessità del codice, portando numerose migliorie.
Ecco uno schema che differenzia il modello di programmazione OOP dalla programmazione procedurale o imperativa vista fino ad ora:
Ogni funzione creata nella parte di sinistra è fine a se stessa e avendo per esempio numerose linee di codice, dovremmo fare molta attenzione a tenere tutto sotto controllo, perchè non abbiamo una delineazione ben precisa del nostro oggetto. Pensiamo ad un oggetto clienti, con le funzioni, dovendo implementare eventuali nuove caratteristiche dovremmo modificare le funzioni interessate con notevoli rischi di errore.
Con l’OOP avremmo creato l’oggetto clienti estendendolo con nuove funzionalità lasciando intatta la struttura dell’oggetto originale.
In OOP si definisce un oggetto nei termini dei dati che lo caratterizzano, cercando di mantenerli il più possibile nascosti al di fuori dell’oggetto e delle funzioni chiamati metodi, per lavorare con questi dati, richiamabili per lavorare su quelli e altri dati. Sostanzialmente l’oggetto è una capsula (tipo le graffe delle funzioni) che mantiene uniti dati e metodi che sono tra loro correlati.
Se dobbiamo estendere un oggetto, per esempio bicicletta, con delle particolarità, col procedurale devo ricopiarmi il codice precedentemente scritto e aggiungerne ulteriore. Se devo fare una modifica, dovrò riportarla su tutto il codice copiato. Se ho un errore lo ritroverò su tutto il codice, oltre ad avere numerose linee di codice ripetuto. Con l’OOP, grazie al concetto di ereditarietà, avrò l’oggetto biciclettai stanziato solo una volta, mentre la mountain bike prenderà già tutte le caratteristiche della bicicletta aggiungendo quelle specifiche che caratterizzano.
In altri linguaggi come il C++, il Java, il C# prima di definire un oggetto devo definirne la classe che ne determina l’incapsulamento dell’oggetto:
Una volta creata la classe non abbiamo definito ancora l’oggetto, che dovrà essere stanziato con quella classe ed ereditarne le proprietà.
In JS la creazione, dichiarazione o istanza di un oggetto è molto più semplice:
let nome = {};
Ho creato un nuovo oggetto vuoto chiamato nome, l’incapsulamento di questo oggetto è quello racchiuso tra parentesi graffe.
Creiamo un oggetto punto che avrà come proprietà le sue coordinate cartesiane ( x e y )
let punto = {}; writeln(punto);
Eseguendo il codice il browser mi mostra che ho creato un oggetto:
[object Object]
Negli altri linguaggi sopra menzionati dovrei creare anche una classe vuota e per aggiungere le proprietà x, y andare ad aggiungerle nella classe, in js invece le specifico al volo:
let punto = {}; writeln(punto); punto.x = 100; punto.y = 200; writeln(punto.x + punto.y);
In js non essendoci le classi (almeno prima di ES6) c’è un nome che descrive questo modello di oggetto: per prototipazione che ci permette di definire un prototipo o modello che ci permette di creare nuovi oggetti senza partire da zero.
3 modi per creare un oggetto
- Creo un oggetto cliente con proprietà nome e cognome
let cliente = { cognome:"Rossi", nome:"Mario" };
Ecco la vera natura interna per js, una collezione di coppie chiave / valore cioè un identificatore (cognome e nome) due punti, un’espressione che ne determina il valore (Rossi e Mario).
- Creiamo lo stesso oggetto cliente senza proprietà, in altre parole un oggetto vuoto
let cliente = {};
aggiungiamo le proprietà successivamente
cliente.nome = "Mario"; cliente.cognome="Rossi";
- Sfruttiamo l’oggetto predefinito Object() e usiamo il costrutto new Object
let cliente = new Object();
aggiungiamo le proprietà successivamente come fatto prima
cliente.nome = "Mario"; cliente.cognome="Rossi";
Richiamare le proprietà degli oggetti
Dato il seguente oggetto:
let gatto = { nome:"Ciccio", razza:"europeo", mantello:"tigrato" };
Esistono 2 modi per richiamare le proprietà di un oggetto,
il primo ha una sintassi simile agli array, è da usare quando una proprietà inizia con un numero
document.write(gatto["razza"]);
Il secondo è molto più agile ed è da preferirsi a priori
document.write(gatto.mantello);
Aggiungere i metodi
Ecco come si aggiungono i metodi:
let cliente = { cognome:"Rossi", nome:"Mario", Nominativo: function() { return cognome + " " + nome } }; writeln(cliente.Nominativo);
In questo caso writeln non stamperà il risultato del metodo Nominativo, ovvero Rossi Mario, ma proprio il valore del metodo
function () { return cognome + " " + nome }
Per eseguire il metodo dobbiamo aggiungere le parentesi tonde per identificarlo
writeln(cliente.Nominativo() );
a questo punto eseguendo il codice riceveremo un errore di variabile cognome not defined.
Questo avviene perchè nel contesto di un oggetto, un metodo (o funzione) può riferirsi alle proprietà (o variabili) dell’oggetto stesso, solo utilizzando un puntatore all’oggetto stesso identificato con this :
let cliente = { cognome:"Rossi", nome:"Mario", Nominativo: function() { return this.cognome + " " + this.nome } }; writeln(cliente.Nominativo());
il this.cognome si riferisce a cliente.cognome.
Quindi quando si usa il this nel contesto di una funzione di un oggetto, il this punta all’oggetto stesso.