DEFINIZIONE DI CLASSE
Nella programmazione orientata agli oggetti una classe è un costrutto di un linguaggio di programmazione usato come modello per creare oggetti. Il modello comprende attributi e metodi che saranno condivisi da tutti gli oggetti creati (istanze) a partire dalla classe. Un “oggetto” è, di fatto, l’istanza di una classe. Nel JavaScript moderno c’è un costrutto “class” più avanzato, che introduce nuove possibilità molto utili per la programmazione ad oggetti.
LA SINTASSI DI CLASS
class MyClass {
// metodi della classe
constructor() { … }
method1() { … }
method2() { … }
method3() { … }
…
}
new MyClass() creerà un nuovo oggetto con tutti i metodi presenti nella classe. Il metodo constructor() viene chiamato automaticamente da new, dunque possiamo usarlo per inizializzare l’oggetto.
Per esempio:
class User {
constructor(name) {
this.name = name;
}
sayHi() {
alert(this.name);
}
}
// Utilizzo:
let user = new User(“John”);
user.sayHi();
Quando viene chiamato new User(“John”):
- Viene creato un nuovo oggetto;
- Il metodo constructor() viene richiamato e assegna a this.name l’argomento passato.
…Ora possiamo chiamare i metodi, per esempio user.sayHi.
COS’E’ UNA CLASSE
Dunque, cos’è esattamente una classe? A differenza di ciò che si potrebbe pensare, non si tratta di un concetto completamente nuovo. Vediamo quindi cos’è effettivamente una classe. Questo ci aiuterà a comprendere aspetti più complessi. In JavaScript, una classe è una specie di funzione.
Osserva:
class User {
constructor(name) { this.name = name; }
sayHi() { alert(this.name); }
}
// prova: User è una funzione
alert(typeof User); // function
Il costrutto class User {…} dunque:
- Crea una funzione chiamata User, che diventa il risultato della dichiarazione della classe. Le istruzioni della funzione provengono dal metodo constructor (considerato vuoto se non presente);
- Salva tutti i metodi (come sayHi) all’interno di User.prototype.
Quando richiameremo da un oggetto un metodo, questo verrà preso dal prototipo (prototype). Dunque, un oggetto creato con la sintassi new User ha accesso ai metodi della classe.
Possiamo rappresentare il risultato della dichiarazione di class User come:
Il codice seguente ti permetterà di analizzarlo:
class User {
constructor(name) { this.name = name; }
sayHi() { alert(this.name); }
}
// una classe è una funzione
alert(typeof User); // function
// …o, più precisamente, il costruttore
alert(User === User.prototype.constructor); // true
// I metodi sono in User.prototype:
alert(User.prototype.sayHi); // il codice del metodo sayHi
// ci sono due funzioni all’interno del prototipo
alert(Object.getOwnPropertyNames(User.prototype)); // constructor, sayHi
// la classe User usando solo funzioni
// 1. Costruttore
function User(name) {
this.name = name;
}
// tutte le funzioni hanno un costruttore predefinito (di default)
// dunque non va creato
// 2. Aggiungiamo un metodo al prototipo
User.prototype.sayHi = function() {
alert(this.name);
};
// Utilizzo:
let user = new User(“John”);
user.sayHi();
Il risultato di questo codice è circa lo stesso. È quindi logico pensare che class sia solo una semplificazione sintattica (syntax sugar). Ci sono però delle importanti differenze. Una funzione creata attraverso class viene etichettata dalla speciale proprietà interna [[IsClassConstructor]]: true. Quindi non è esattamente uguale che crearla manualmente. A differenza di una normale funzione, il costruttore di una classe può essere richiamato solo attraverso la parola chiave new:
class User {
constructor() {}
}
alert(typeof User); // funzione
User(); // Errore: Il costruttore della classe può essere richiamato solo attraverso ‘new’
Inoltre, nella maggior parte dei motori JavaScript il costruttore comincia con “class”
class User {
constructor() {}
}
alert(User); // class User { … }
- Ci sono altre differenze, che scopriremo più avanti.
- I metodi delle classi non sono enumerabili. La definizione di una classe imposta il flag enumerable a false per tutti i metodi all’interno di “prototype”.
Questo è un bene, dato che non vogliamo visualizzare i metodi quando utilizziamo un ciclo for..in per visualizzare un oggetto.
- Il contenuto di una classe viene sempre eseguito in strict mode.
Oltre a queste, la sintassi class apporta altre caratteristiche, che esploreremo più avanti.
L’ESPRESSIONE CLASS
Come le funzioni, le classi possono essere definite all’interno di un’altra espressione, passata come parametro, essere ritornata (returned), assegnata (assigned) etc.
Qui c’è un piccolo esempio:
let User = class {
sayHi() {
alert(“Hello”);
}
};
In maniera simile alle funzioni nominate (Named Function Expression), le classi possono avere o meno un nome. Se una classe ha un nome, esso è visibile solo all’interno della classe:
// “Named Class Expression”
let User = class MyClass {
sayHi() {
alert(MyClass); // MyClass è visibile solo all’interno della classe
}
};
new User().sayHi(); // funziona, restituisce la definizione di MyClass
alert(MyClass); // errore, MyClass non è visibile al di fuori della classe
GETTER E SETTER
Così come negli oggetti letterali (literal objects), le classi possono includere getters/setters, generatori, proprietà eccetera.
L’esempio seguente implementa user.name attraverso get/set:
class User {
constructor(name) {
// invoca il setter
this.name = name;
}
get name() {
return this._name;
}
set name(value) {
if (value.length < 4) {
alert(“Name is too short.”);
return;
}
this._name = value;
}
}
let user = new User(“John”);
alert(user.name); // John
user = new User(“”); // Nome troppo corto.
Negli esempi riportati sopra, la classe User conteneva solo dei metodi. Aggiungiamo una proprietà:
class User {
name = “Mario Rossi”;
sayHi() {
alert(`Hello, ${this.name}!`);
}
}
new User().sayHi();
Quindi scriviamo semplicemente ” = ” nella dichiarazione. La differenza importante dei campi di una classe è che vengono impostati sull’oggetto individuale e non su User.prototype:
class User {
name = “John”;
}
let user = new User();
alert(user.name); // John
alert(User.prototype.name); // undefined
APPROFONDIMENTO AI
Le classi in JavaScript sono un modo per definire oggetti e loro comportamenti. Anche se JavaScript non è un linguaggio orientato agli oggetti puro (come Java o C++), con l’introduzione di ECMAScript 6 (ES6), sono state aggiunte le classi per facilitare la creazione di oggetti e per fornire una sintassi più familiare agli sviluppatori che provengono da linguaggi orientati agli oggetti.
Cos’è una classe?
Una classe in JavaScript è essenzialmente uno schema o un modello per creare oggetti. Definisce le proprietà e i metodi che gli oggetti creati a partire da essa avranno. È un modo di definire oggetti in modo più strutturato, mantenendo la stessa funzionalità che si potrebbe ottenere usando le funzioni costruttori e i prototipi (precedente a ES6).
Definizione di una classe
Ecco un esempio di base di una classe in JavaScript:
class Persona {
constructor(nome, eta) {
this.nome = nome;
this.eta = eta;
}
descrizione() {
return `${this.nome} ha ${this.eta} anni.`;
}
}
const persona1 = new Persona(“Mario“, 30);
console.log(persona1.descrizione()); // “Mario ha 30 anni.”
Breakdown dell’esempio:
1. Definizione della classe: La classe Persona viene definita usando la parola chiave class. È come un modello per creare oggetti che avranno nome e età.
2. Constructor: Il metodo constructor viene eseguito quando si crea una nuova istanza della classe (con new). In questo caso, accetta due parametri, nome e eta, e li assegna alle proprietà dell’oggetto.
3. Metodo: La classe Persona ha un metodo chiamato descrizione, che restituisce una stringa con il nome e l’età della persona. Questo metodo sarà disponibile su tutte le istanze della classe.
Costruttore (constructor)
Il costruttore è un metodo speciale per inizializzare le proprietà dell’oggetto. Può accettare parametri che vengono utilizzati per impostare i valori di proprietà.
class Auto {
constructor(modello, anno) {
this.modello = modello;
this.anno = anno;
}
}
In questo caso, quando si crea una nuova auto, si può passare il modello e l’anno che verranno memorizzati come proprietà dell’oggetto.
const auto1 = new Auto(“Fiat“, 2021);
console.log(auto1.modello); // “Fiat”
console.log(auto1.anno); // 2021
Metodi
Le classi possono avere metodi per definire comportamenti. Come già visto, il metodo descrizione in Persona è un esempio. I metodi all’interno delle classi non richiedono la parola chiave function.
class Cerchio {
constructor(raggio) {
this.raggio = raggio;
}
// Metodo per calcolare l’area del cerchio
area() {
return Math.PI * this.raggio * this.raggio;
}
}
const cerchio1 = new Cerchio(5);
console.log(cerchio1.area()); // 78.53981633974483
Proprietà Statiche e Metodi Statici
Le proprietà statiche e i metodi statici appartengono alla classe stessa e non alle singole istanze. Ciò significa che non possono essere invocati su un’istanza della classe, ma solo sulla classe direttamente.
Esempio di metodo statico:
class Matematica {
static somma(a, b) {
return a + b;
}
}
console.log(Matematica.somma(2, 3)); // 5
In questo esempio, il metodo somma può essere chiamato direttamente sulla classe Matematica, senza creare un’istanza di essa.
Ereditarietà (Inheritance)
JavaScript supporta anche l’ereditarietà tra classi. La parola chiave extends consente di creare una nuova classe basata su una classe esistente.
Ecco un esempio di ereditarietà:
class Animale {
constructor(nome) {
this.nome = nome;
}
parla() {
console.log(`${this.nome} fa un suono.`);
}
}
class Cane extends Animale {
parla() {
console.log(`${this.nome} abbaia.`);
}
}
const cane = new Cane(“Fido“);
cane.parla(); // “Fido abbaia.”
Breakdown dell’esempio:
1. Classe base (superclasse): La classe Animale è una classe generica con un costruttore che accetta un nome e un metodo parla che emette un messaggio generico.
2. Classe derivata (sottoclasse): La classe Cane estende Animale utilizzando la parola chiave extends. Tuttavia, ridefinisce (o sovrascrive) il metodo parla per fornire un comportamento specifico per i cani.
3. super: Quando una sottoclasse vuole accedere al costruttore della sua superclasse, può usare la parola chiave super. Viene generalmente usato nel costruttore della sottoclasse per chiamare il costruttore della superclasse.
class Gatto extends Animale {
constructor(nome, razza) {
super(nome); // chiama il costruttore della classe genitore (Animale)
this.razza = razza;
}
parla() {
console.log(`${this.nome} miagola.`);
}
}
const gatto = new Gatto(“Whiskers“, “Siamese“);
gatto.parla(); // “Whiskers miagola.”
In questo esempio, super(nome) viene chiamato nel costruttore di Gatto per inizializzare la proprietà nome della classe base Animale.
Getters e Setters
Le classi possono anche avere getter e setter, che consentono di definire metodi che agiscono come proprietà.
class Rettangolo {
constructor(lunghezza, larghezza) {
this.lunghezza = lunghezza;
this.larghezza = larghezza;
}
// Getter per l’area
get area() {
return this.lunghezza * this.larghezza;
}
// Setter per modificare la lunghezza
set nuovaLunghezza(valore) {
this.lunghezza = valore;
}
}
const rettangolo = new Rettangolo(10, 5);
console.log(rettangolo.area); // 50 (usa il getter)
rettangolo.nuovaLunghezza = 20; // usa il setter
console.log(rettangolo.area); // 100
In questo esempio, l’area del rettangolo viene calcolata tramite un getter, mentre la lunghezza può essere modificata tramite un setter.
Classi anonime ed espressioni di classe
È possibile definire una classe anonima o usare una espressione di classe, cioè una classe che non ha un nome o che viene definita all’interno di un’espressione:
let Utente = class {
constructor(nome) {
this.nome = nome;
}
saluta() {
console.log(`Ciao ${this.nome}`);
}
};
const utente = new Utente(“Luigi“);
utente.saluta(); // “Ciao Luigi”
Riassunto
•Le classi in JavaScript forniscono un modo più semplice e organizzato di creare oggetti.
•La parola chiave class è stata introdotta con ES6 per creare modelli per oggetti.
•Il costruttore è un metodo speciale utilizzato per inizializzare le proprietà dell’oggetto quando viene creata una nuova istanza.
•I metodi definiti nelle classi sono funzioni associate agli oggetti creati dalla classe.
•Le classi possono ereditare da altre classi utilizzando extends, e si può accedere ai membri della superclasse con super.
•I getter e i setter forniscono un modo per ottenere o impostare valori come se fossero proprietà, ma in realtà si tratta di metodi.
Le classi in JavaScript rappresentano un’evoluzione della gestione degli oggetti, introducendo una sintassi più moderna e semplificando alcune operazioni rispetto al tradizionale approccio basato sui prototipi.
Scrivi un commento