Introduzione alle Classi
In JavaScript, una classe è un tipo di funzione utilizzata per creare oggetti e implementare il concetto di ereditarietĂ . Le classi forniscono un modo piĂš chiaro e sintetico per creare oggetti e gestire lâereditarietĂ rispetto alle funzioni costruttrici e al pattern di ereditarietĂ basato su prototipi esistenti in JavaScript prima dellâintroduzione delle classi in ES6 (ECMAScript 2015).
Struttura di una Classe
Una classe in JavaScript può essere definita utilizzando la parola chiave class
, seguita dal nome della classe e da un blocco di codice che racchiude i suoi metodi. Esempio:
class MyClass {
// Metodi della classe
}
Il Costruttore
Il metodo constructor
è un metodo speciale di una classe. Viene utilizzato per creare e inizializzare un oggetto creato con una classe. Câè solo un metodo constructor
in una classe, e se si tenta di definirne piĂš di uno, si verificherĂ un errore di sintassi.
Il constructor
viene chiamato automaticamente quando si crea unâistanza della classe con new
.
Esempio:
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
}
const person1 = new Person("Alice", 30);
console.log(person1.name); // Alice
console.log(person1.age); // 30
Estendere una Classe con extends
La parola chiave extends
in JavaScript viene utilizzata per creare una classe figlia di unâaltra classe. Questo è il modo per implementare lâereditarietĂ tra classi in JavaScript.
Esempio:
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a noise.`);
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name); // Chiama il costruttore della classe padre
this.breed = breed;
}
speak() {
console.log(`${this.name} barks.`);
}
}
const dog = new Dog("Rex", "Golden Retriever");
dog.speak(); // Rex barks.
Uso di super
La parola chiave super
viene utilizzata in due modi: come funzione e come oggetto.
- Come funzione,
super
chiama il costruttore della classe padre. Ă obbligatorio chiamare il costruttore del genitore prima di accedere athis
in una classe figlia. - Come oggetto,
super
è usato per chiamare metodi del genitore da metodi della classe figlia.
Esempio di super
come oggetto:
class Cat extends Animal {
speak() {
super.speak(); // Chiama il metodo speak del genitore
console.log(`${this.name} meows.`);
}
}
const cat = new Cat("Mia");
cat.speak(); // Mia makes a noise. Mia meows.
Conclusione
Le classi in JavaScript offrono un modo chiaro e conciso per lavorare con lâereditarietĂ e per organizzare e strutturare il codice in modo orientato agli oggetti. Attraverso lâuso del costruttore, extends
, e super
, JavaScript fornisce un modello robusto e flessibile per la definizione e lâestensione di classi.
I metodi static
Un metodo statico in una classe è un metodo che appartiene alla classe stessa piuttosto che a qualsiasi istanza specifica della classe. Questo significa che un metodo statico può essere chiamato sulla classe direttamente, senza dover creare unâistanza della classe. I metodi statici sono utili per implementare funzionalitĂ che sono relative alla classe nel suo complesso piuttosto che a un oggetto specifico creato dalla classe.
Ecco le principali differenze tra metodi statici e non statici (o metodi dâistanza):
-
Chiamata del metodo:
- Un metodo statico viene chiamato sulla classe stessa. Ad esempio, se hai una classe
MathUtils
con un metodo staticoadd
, lo chiameresti comeMathUtils.add()
. - Un metodo dâistanza viene chiamato su unâistanza della classe. Ad esempio, se hai una classe
Calculator
con un metodo dâistanzasubtract
, devi prima creare unâistanza (let calc = new Calculator()
) e poi chiamare il metodo su quellâistanza (calc.subtract()
).
- Un metodo statico viene chiamato sulla classe stessa. Ad esempio, se hai una classe
-
Uso della parola chiave
this
:- In un metodo statico,
this
fa riferimento alla classe stessa. Ciò significa che non puoi accedere direttamente alle proprietĂ dâistanza della classe allâinterno di un metodo statico, poichĂŠ non câè un oggetto dâistanza. - In un metodo dâistanza,
this
fa riferimento allâoggetto specifico (istanza) su cui il metodo viene chiamato, consentendo lâaccesso alle sue proprietĂ e metodi.
- In un metodo statico,
-
Scopo e utilizzo:
- I metodi statici sono spesso utilizzati per operazioni utility o funzioni che non richiedono dati da unâistanza specifica della classe. Ad esempio, una funzione di aiuto per validare un indirizzo email potrebbe essere un metodo statico in una classe di utilitĂ .
- I metodi dâistanza sono utilizzati per operazioni che richiedono o modificano lo stato di unâistanza specifica della classe.
-
EreditarietĂ :
- I metodi statici possono essere ereditati in una sottoclasse, ma il loro
this
si riferirĂ sempre alla classe su cui sono stati definiti, non alla classe derivata, a meno che non vengano esplicitamente richiamati sulla sottoclasse. - I metodi dâistanza possono essere sovrascritti nelle sottoclassi, fornendo implementazioni specifiche che possono fare uso delle proprietĂ di quella sottoclasse.
- I metodi statici possono essere ereditati in una sottoclasse, ma il loro
Ecco un semplice esempio per illustrare un metodo statico rispetto a un metodo dâistanza:
class MathUtils {
static add(a, b) {
return a + b; // Metodo statico
}
subtract(a, b) {
return a - b; // Metodo d'istanza
}
}
// Chiamata del metodo statico direttamente sulla classe
console.log(MathUtils.add(5, 3)); // 8
// Chiamata del metodo d'istanza su un'istanza della classe
const util = new MathUtils();
console.log(util.subtract(10, 4)); // 6
In questo esempio, add
è un metodo statico che può essere chiamato direttamente su MathUtils
, mentre subtract
è un metodo dâistanza che richiede un oggetto MathUtils
per essere chiamato.
Metodi Statici nelle Classi
Oltre ai metodi dâistanza che operano su dati specifici dellâoggetto, le classi in JavaScript possono anche avere metodi statici. I metodi statici sono chiamati sulla classe stessa, non su istanze della classe. Sono spesso utilizzati per operazioni che non richiedono dati da unâistanza della classe.
Definizione di un Metodo Statico
Per definire un metodo statico, usi la parola chiave static
prima del nome del metodo allâinterno della classe. Ecco un esempio:
class MathUtils {
static sum(a, b) {
return a + b;
}
}
console.log(MathUtils.sum(5, 10)); // 15
In questo esempio, sum
è un metodo statico della classe MathUtils
e può essere chiamato direttamente sulla classe.
Getter e Setter
JavaScript supporta anche i getter e i setter nelle classi, permettendoti di avere un controllo piĂš fine sullâaccesso e la modifica delle proprietĂ di un oggetto.
Esempio:
class Person {
constructor(name) {
this._name = name; // L'uso di un underscore è una convenzione per indicare una proprietà "privata"
}
get name() {
return this._name;
}
set name(value) {
if (value.length < 4) {
console.log("Il nome deve avere almeno 4 caratteri.");
return;
}
this._name = value;
}
}
let person = new Person("Alice");
console.log(person.name); // Alice
person.name = "Al"; // Il nome deve avere almeno 4 caratteri.
console.log(person.name); // Alice (non cambiato)
I getter e i setter ti permettono di eseguire logica aggiuntiva ogni volta che accedi o modifichi una proprietĂ , come la validazione dei dati in questo esempio.
Metodi Privati nelle Classi JavaScript e TypeScript*
Nellâambito della programmazione orientata agli oggetti, i metodi privati di una classe sono metodi che non possono essere chiamati o accessibili dallâesterno della classe. Questo concetto supporta lâincapsulamento e lâastrazione, consentendo agli sviluppatori di nascondere i dettagli di implementazione e di esporre solo le parti necessarie di un oggetto.
Metodi Privati in JavaScript
Con lâintroduzione di ECMAScript 2015 (ES6), JavaScript ha introdotto il concetto di classi, ma senza un supporto nativo per i metodi privati. Tuttavia, con ECMAScript 2020 (ES2020), JavaScript ha introdotto una sintassi per i campi privati e i metodi privati nelle classi, utilizzando il prefisso #
.
Sintassi dei Metodi Privati
class MyClass {
#myPrivateMethod() {
console.log("Questo è un metodo privato.");
}
publicMethod() {
this.#myPrivateMethod(); // Chiamata interna al metodo privato
}
}
const myInstance = new MyClass();
myInstance.publicMethod(); // Funziona
myInstance.#myPrivateMethod(); // Errore! Il metodo è privato e non accessibile dall'esterno.
In questo esempio, #myPrivateMethod
è un metodo privato accessibile solo allâinterno della definizione della classe MyClass
.
Metodi Privati in TypeScript
TypeScript estende JavaScript aggiungendo tipi e altre funzionalitĂ , tra cui un miglior supporto per lâincapsulamento tramite la parola chiave private
.
Utilizzo della Parola Chiave private
In TypeScript, puoi segnare un metodo come privato usando la parola chiave private
. Questo impedisce che il metodo venga chiamato al di fuori della classe.
class MyClass {
private myPrivateMethod() {
console.log("Questo è un metodo privato.");
}
publicMethod() {
this.myPrivateMethod(); // Chiamata interna al metodo privato
}
}
const myInstance = new MyClass();
myInstance.publicMethod(); // Funziona
myInstance.myPrivateMethod(); // Errore TypeScript, ma attenzione...
Limitazioni
Anche se TypeScript segnala un errore quando si tenta di accedere a un metodo privato dallâesterno della classe, è importante notare che questa è una restrizione a livello di linguaggio impostata da TypeScript. Quando il codice TypeScript viene compilato in JavaScript, la distinzione tra metodi privati e pubblici non persiste nello stesso modo, perchĂŠ JavaScript fino a ES2019 non supportava nativamente i metodi privati.
Con lâintroduzione dei metodi privati in ES2020, TypeScript può ora sfruttare questa caratteristica di JavaScript per i progetti che vengono compilati con un target di ES2020 o successivo.
Conclusioni
I metodi privati sono uno strumento essenziale nellâincapsulamento e nellâastrazione della programmazione orientata agli oggetti, consentendo di nascondere i dettagli di implementazione di una classe. In JavaScript, lâuso di metodi privati è diventato possibile con ES2020, mentre TypeScript ha fornito un supporto sintattico per lâincapsulamento fin dalla sua introduzione, con alcune limitazioni nella compilazione verso versioni precedenti di JavaScript. Ă cruciale comprendere queste differenze e limitazioni quando si lavora con classi e incapsulamento in TypeScript e JavaScript.