JavaScript, essendo un linguaggio versatile, permette di sviluppare software seguendo differenti approcci di programmazione: funzionale, orientato agli oggetti e imperativo.
Per supportare il paradigma orientato agli oggetti, JavaScript offre le classi. Data la loro importanza, questo articolo si propone come guida per comprenderne la natura e l’utilizzo.
Che cosa sono le Classi in JavaScript?
Nella programmazione orientata agli oggetti, i sistemi vengono modellati come insiemi di oggetti interagenti. Gli oggetti, per funzionare, conservano dati nelle loro proprietà e compiono azioni tramite i loro metodi. Una classe definisce le caratteristiche, in termini di proprietà e metodi, degli oggetti di un determinato tipo. In sostanza, le classi fungono da progetti per la creazione di oggetti.
Terminologia essenziale delle classi
Per garantire una comprensione condivisa, ecco una panoramica dei termini chiave relativi alle classi. Se hai già familiarità con la programmazione orientata agli oggetti, puoi saltare alla sezione successiva.
❇️ Una classe è un modello per la creazione di oggetti. Fornisce uno schema per generare istanze di un certo tipo. La creazione di un oggetto a partire dal modello definito dalla classe è denominata “istanzazione”.
❇️ Un membro di una classe è tutto ciò che appartiene a essa. I membri si dividono in due categorie: metodi e proprietà.
❇️ Una proprietà è un membro di una classe dedicato alla memorizzazione di valori, che possono essere semplici (numeri, stringhe) o complessi (oggetti, array).
❇️ Alcune proprietà, denominate “private”, sono accessibili solo all’interno della classe, mentre altre, “pubbliche”, sono accessibili sia dall’interno che dall’esterno.
❇️ Un metodo è una funzione interna alla classe, quindi legata a essa e con accesso a proprietà sia pubbliche che private. Come per le proprietà, esistono metodi pubblici e metodi privati.
❇️ Esistono metodi specifici, getter e setter, che permettono al codice esterno alla classe di interagire con le proprietà interne. I getter recuperano i valori delle proprietà, mentre i setter li modificano.
❇️ Alcuni membri sono “statici”, il che significa che si riferiscono alla classe stessa, non alle sue istanze.
Di contro, i membri non statici sono accessibili solo tramite istanze della classe. È necessario quindi creare un’istanza prima di poterli usare.
Durante la creazione di un’istanza, viene invocato un metodo speciale, detto “costruttore”, per inizializzare le proprietà dell’istanza.
Spiegazione del processo di Istanziazione
Per creare un’istanza di una classe in JavaScript, si usa la parola chiave new
seguita dal nome della classe. Ad esempio, per creare un’istanza della classe Array
:
const myArr = new Array()
Come Creare Classi in JavaScript
In questa sezione, creeremo una classe che implementi tutti i concetti discussi nella sezione sulla terminologia. Lo faremo attraverso una serie di esempi, dove ogni esempio si basa su quelli precedenti.
Dichiarazione di una Classe Vuota
Per definire una classe in JavaScript, usiamo la parola chiave class
, seguita dal nome della classe. Poi, definiamo il corpo della classe, racchiuso tra parentesi graffe, contenente tutti i membri.
Ecco un esempio di una classe con un corpo vuoto:
class Dog { }
Ora possiamo istanziare la classe e stamparla:
const pet = new Dog; console.log(pet);
Creazione di Proprietà Pubbliche
Le proprietà pubbliche sono definite con un identificatore e, opzionalmente, un valore iniziale.
class Dog { name = "Roy"; age; }
Qui abbiamo definito la proprietà name
con un valore stringa e age
senza un valore iniziale.
const pet = new Dog(); console.log(pet.name); console.log(pet.age);
Definizione di Metodi Pubblici
Possiamo aggiungere metodi alla classe all’interno del suo corpo. Un metodo viene definito come una normale funzione, ma senza la parola chiave function
.
class Dog { name = "Roy"; age; walk () { console.log("Walking"); } }
Nell’esempio, abbiamo definito il metodo walk
. Ogni istanza della classe Dog
avrà questo metodo.
const pet = new Dog(); pet.walk();
Accesso alle Proprietà dai Metodi
In JavaScript, si accede normalmente alle proprietà di un oggetto tramite l’operatore punto. Ad esempio, per accedere alla proprietà name
di un oggetto person
, useremmo person.name
.
Tuttavia, all’interno di un oggetto, per riferirsi alle sue proprietà si usa la parola chiave this
, ad esempio this.name
.
La parola chiave this
si riferisce all’oggetto corrente. Quindi, per accedere alle proprietà della classe dai suoi metodi, useremmo la sintassi this.nome_proprieta
.
Creazione di Proprietà Private
Supponiamo di voler rendere private le proprietà name
e age
. Riscriveremmo la classe come segue:
class Dog { #name = "Roy"; #age; walk () { console.log("Walking"); } }
Le proprietà private vengono specificate utilizzando il cancelletto (#
) come prefisso. Se si tenta di accedervi direttamente dall’esterno, si otterrà un errore.
const dog = new Dog(); dog.#name
Creazione di Metodi Getter e Setter
Ora che le proprietà name
e age
sono private, possiamo accedervi solo tramite metodi interni alla classe.
Per permettere al codice esterno di interagire con queste proprietà, definiamo i getter e i setter. Ecco come farlo per la proprietà name
:
class Dog { #name = "Roy"; #age; get name () { return this.#name; } set name (value) { this.#name = value; } walk () { console.log("Walking"); } }
Con questa classe, possiamo impostare e visualizzare il nome usando il codice seguente:
const pet = new Dog(); // Impostazione del nome pet.name = "Rex"; // Recupero del nome console.log(pet.name);
Creazione di Metodi Privati
Come le proprietà, i metodi privati hanno come prefisso il cancelletto. Un metodo privato si dichiarerebbe così:
class Dog { #name = "Roy"; #age; get name () { return this.#name; } set name (value) { this.#name = value; } #increaseAge() { this.#age ++; } #decreaseAge () { this.#age --; } walk () { console.log("Walking"); } }
Se si tenta di accedere a questi metodi dall’esterno della classe, l’operazione fallirà.
const pet = new Dog(); pet.#increaseAge();
Creazione del Metodo Costruttore
È possibile definire un metodo costruttore, che viene invocato automaticamente durante la creazione di una nuova istanza della classe. Il costruttore serve per inizializzare le proprietà. In questo esempio, inizializzeremo le proprietà age
e name
con i valori forniti dall’utente all’atto dell’istanza.
class Dog { #name; #age; constructor (name = "Dog", age = 0) { this.#name = name; this.#age = age; } get name () { return this.#name; } set name (value) { this.#name = value; } #increaseAge() { this.#age ++; } #decreaseAge () { this.#age --; } walk () { console.log("Walking"); } }
Ora, quando creiamo un’istanza della classe, possiamo specificare il nome e l’età.
const pet = new Dog('Roy', 3); console.log(pet.name);
Creazione di Proprietà e Metodi Statici
Come accennato, si può accedere ai membri statici senza istanziare la classe. Nell’esempio, creeremo una proprietà e un metodo statici.
class Dog { #name; #age; static genus = "Canis"; constructor (name = "Dog", age = 0) { this.#name = name; this.#age = age; } static bark() { console.log("Woof"); } get name () { return this.#name; } set name (value) { this.#name = value; } #increaseAge() { this.#age ++; } #decreaseAge () { this.#age --; } walk () { console.log("Walking"); } }
Ora si può accedere alla proprietà e al metodo statico direttamente dalla classe, senza creare un’istanza:
console.log(Dog.genus); Dog.bark();
Ereditarietà
Le classi possono ereditare proprietà e metodi da altre classi. La classe che eredita è detta “sottoclasse” o “classe derivata”, mentre la classe da cui si eredita è detta “superclasse” o “classe base”.
Per definire una sottoclasse in JavaScript, si usa la parola chiave extends
. Ecco un esempio in cui ereditiamo dalla classe Dog
.
class Rottweiler extends Dog { constructor (name, age) { super(name, age); this.breed = 'rottweiler'; } }
La struttura della classe è simile alla precedente, ma nel costruttore abbiamo chiamato la funzione super
, che si riferisce al costruttore della superclasse. Abbiamo quindi invocato il costruttore della classe base, passando nome ed età.
const myPet = new Rottweiler(); console.log(myPet);
Conclusione
In questo articolo abbiamo esplorato le classi, definendone la natura, i tipi di membri e le relative classificazioni. Abbiamo poi illustrato tutti questi concetti con esempi pratici.
Come passo successivo, potresti voler approfondire le domande tipiche dei colloqui di lavoro riguardanti la programmazione orientata agli oggetti.