Skip to content

13. Le classi

Image

Qui introduciamo le classi di ECMAScript 6. Innanzitutto mostriamo che le funzioni possono già essere utilizzate come classi.

13.1. script [class-00]

Il seguente script mostra un utilizzo insolito delle funzioni. Qui vengono utilizzate come oggetti.


'use strict';
// una funzione può essere utilizzata come oggetto

// un guscio vuoto
function f() {

}
// a cui vengono assegnate proprietà dall'esterno
f.prop1 = "val1";
f.show = function () {
  console.log(this.prop1);
}
// uso di f
f.show();

// una funzione g che funziona come una classe
function g() {
  this.prop2 = "val2";
  this.show = function () {
    console.log(this.prop2);
  }
}
// istanziazione della funzione con [new]
new g().show();

Commenti

  • righe 5-7: il corpo della funzione f non definisce alcuna proprietà;
  • righe 9-12: si assegnano proprietà alla funzione f dall’esterno;
  • riga 14: utilizzo della funzione (oggetto) f. Si noti che non si scrive [f()] ma semplicemente [f]. Si tratta della notazione di un oggetto;
  • righe 17-22: si definisce una funzione [g] come se fosse una classe con proprietà e metodi;
  • riga 24: la funzione [g] viene istanziata da [new g()];

Risultati dell’esecuzione


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Data\st-2019\dev\es6\javascript\classes\class-00.js"
val1
val2

ES6 ha introdotto il concetto di classe, che ora ci permette di evitare di ricorrere alle funzioni per ottenere delle classi.

13.2. script [class-01]

Lo script [class-01] presenta una classe [Personne]:


// classe
class Personne {

  // costruttore
  constructor(nom, prénom, âge) {
    this.nom = nom;
    this.prénom = prénom;
    this.âge = âge;
  }

  // getter e setter
  get nom() {
    return this._nom;
  }
  set nom(value) {
    this._nom = value;
  }

  get prénom() {
    return this._prénom;
  }
  set prénom(value) {
    this._prénom = value;
  }

  get âge() {
    return this._âge;
  }
  set âge(value) {
    this._âge = value;
  }

  // da toString a JSON
  toString() {
    return JSON.stringify(this);
  }
}

// chiamata della classe
function main() {
  const personne = new Personne("Poirot", "Hercule", 66);
  console.log("personne=", personne.toString(), typeof (personne), personne instanceof (Personne));
}

// chiamata di main
main();

Commenti

  • riga 2: la parola chiave [class] indica una classe;
  • righe 5-9: la parola chiave [constructor] indica il costruttore della classe. Ne può esserci al massimo uno. Serve a creare e inizializzare un'istanza della classe. Si noti che non vi è alcuna dichiarazione delle proprietà [nom, prénom, âge];
  • righe 11-36: proprietà della classe. Qui si ritrovano elementi già visti nel paragrafo sugli oggetti 4, a pagina 44. Differisce solo la sintassi;
  • riga 41: creazione di un oggetto di tipo [Personne]. Da questo momento in poi l’oggetto [personne] viene utilizzato come un oggetto letterale. [typeof (personne)] è uguale a «object» e l’espressione [personne instanceof (Personne)] è vera. È quindi possibile conoscere il tipo esatto di un’istanza di classe;

Risultati dell’esecuzione


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Data\st-2019\dev\es6\javascript\classes\class-01.js"
personne= {"_nom":"Poirot","_prénom":"Hercule","_âge":66} object true

13.3. script [class-02]

Questo script mostra la possibilità di ereditare da una classe con la parola chiave [extends].

Per prima cosa isoliamo la classe [Personne] in un modulo [Personne.js]:


// classe
class Personne {

  // costruttore
  constructor(nom, prénom, âge) {
    this.nom = nom;
    this.prénom = prénom;
    this.âge = âge;
  }

  // getter e setter
  get nom() {
    return this._nom;
  }
  set nom(value) {
    this._nom = value;
  }

  get prénom() {
    return this._prénom;
  }
  set prénom(value) {
    this._prénom = value;
  }

  get âge() {
    return this._âge;
  }
  set âge(value) {
    this._âge = value;
  }

  // da toString a JSON
  toString() {
    return JSON.stringify(this);
  }
}
// classe di esportazione
export default Personne;
  • riga 39: esportiamo la classe [Personne] affinché gli script possano importarla;

Lo script [class-02] crea una classe [Enseignant] derivata dalla classe [Personne]:


// importazioni
import Personne from './Personne';

// classe
class Enseignant extends Personne {

  // costruttore
  constructor(nom, prénom, âge, discipline) {
    super(nom, prénom, âge);
    this.discipline = discipline;
  }

  // getter e setter
  get discipline() {
    return this._discipline;
  }
  set discipline(value) {
    this._discipline = value;
  }

}

// chiamata della classe
function main() {
  const enseignant = new Enseignant("Poirot", "Hercule", 66, "détective");
  console.log("enseignant=", enseignant.toString(), typeof (enseignant), enseignant instanceof Enseignant);
}

// chiamata di main
main();

Commenti

  • riga 2: si importa la classe [Personne] dal modulo [Personne.js], che si trova nella stessa cartella di [class-02];
  • riga 5: la classe [Enseignant] estende (eredita da) la classe [Personne] con la parola chiave [extends]: aggiunge una proprietà [_discipline] con i relativi getter e setter;
  • righe 8-11: il costruttore della classe [Enseignant] riceve quattro valori per inizializzare le quattro proprietà della classe;
  • riga 9: la parola chiave [super] richiama il costruttore della classe padre [Personne], che inizializzerà quindi le proprietà [_nom, _prénom, _âge];
  • riga 10: si inizializza la proprietà [_discipline], che appartiene alla classe [Enseignant];
  • righe 14-19: il getter e il setter della proprietà [_discipline];
  • riga 25: si crea un oggetto di tipo [Enseignant];
  • riga 26: si utilizza il metodo [enseignant.toString()]. La classe [Enseignant] non dispone di questo metodo. Viene quindi automaticamente utilizzato quello della sua classe padre. Questo metodo fa sì che l’espressione [JSON.stringify(this)], dove [this] sarà in questo caso un oggetto [Enseignant] e non un oggetto [Personne]. Questo è ciò che nella programmazione orientata agli oggetti si chiama polimorfismo delle classi. Un termine altisonante per JavaScript, che non è un linguaggio orientato agli oggetti. Tuttavia, JavaScript fa qui ciò che ci si aspetta da lui: visualizza correttamente un insegnante;

I risultati dell’esecuzione sono i seguenti:


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Data\st-2019\dev\es6\javascript\classes\class-02.js"
enseignant= {"_nom":"Poirot","_prénom":"Hercule","_âge":66,"_discipline":"détective"} object true
  • riga 2: JavaScript riconosce correttamente che la variabile [enseignant] è di tipo [Enseignant];

13.4. script [class-03]

Lo script [class-03] mostra che una classe figlia può ridefinire proprietà e metodi della sua classe padre. In questo caso, ridefiniamo il metodo [toString] della classe padre:


// importazioni
import Personne from './Personne';

// classe
class Enseignant extends Personne {

  // costruttore
  constructor(nom, prénom, âge, discipline) {
    super(nom, prénom, âge);
    this.discipline = discipline;
  }

  // getter e setter
  get discipline() {
    return this._discipline;
  }
  set discipline(value) {
    this._discipline = value;
  }

  // ridefinizione di toString
  toString() {
    return "[Enseignant]" + JSON.stringify(this);
  }
}

// chiamata della classe
function main() {
  const enseignant = new Enseignant("Poirot", "Hercule", 66, "détective");
  console.log("enseignant=", enseignant.toString(), typeof (enseignant), enseignant instanceof Enseignant);
}

// chiamata di main
main();

I risultati dell’esecuzione sono i seguenti:


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Data\st-2019\dev\es6\javascript\classes\class-03.js"
enseignant= [Enseignant]{"_nom":"Poirot","_prénom":"Hercule","_âge":66,"_discipline":"détective"} object true

13.5. script [class-04]

Lo script [class-04] mostra nuovamente il polimorfismo in azione: laddove una funzione si aspetta un parametro formale di tipo [Personne], è possibile passare un tipo derivato come [Enseignant]. Infatti, in virtù della derivazione, il tipo [Enseignant] possiede tutti gli attributi del tipo [Personne].

Per prima cosa, isoliamo il tipo [Enseignant] in un modulo [Enseignant.js]:


// importazioni
import Personne from './Personne';

// classe
class Enseignant extends Personne {

  // costruttore
  constructor(nom, prénom, âge, discipline) {
    super(nom, prénom, âge);
    this.discipline = discipline;
  }

  // getter e setter
  get discipline() {
    return this._discipline;
  }
  set discipline(value) {
    this._discipline = value;
  }

}

// classe esportata
export default Enseignant;
  • riga 24: la classe [Enseignant] viene esportata affinché altri script possano importarla;

Lo script [class-04] è il seguente:


// importazioni
import Enseignant from './Enseignant';
import Personne from './Personne';

// funzione che accetta una persona come parametro
function show(personne) {
  // in ogni caso
  console.log("paramètre=", personne.toString(), typeof (personne));
  // istanza di Persona
  if (personne instanceof Personne) {
    console.log("personne=", personne.toString());
  }
  // istanza di Insegnante
  if (personne instanceof Enseignant) {
    console.log("enseignant=", personne.toString());
  }
}

// chiamata di show con un insegnante
show(new Enseignant("Poirot", "Hercule", 66, "détective"));
show(new Personne("Marple", "Miss", 70));
  • riga 6: la funzione [show] richiede un tipo [Personne] o derivato;
  • riga 8: vengono visualizzati la stringa del parametro e il suo tipo. Troveremo [object];
  • righe 10-16: è possibile determinare se si tratta di un tipo [Personne] o di un tipo [Enseignant]. Il codice può quindi essere adattato al tipo effettivo del parametro;

I risultati dell’esecuzione sono i seguenti:


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Data\st-2019\dev\es6\javascript\classes\class-04.js"
paramètre= {"_nom":"Poirot","_prénom":"Hercule","_âge":66,"_discipline":"détective"} object
personne= {"_nom":"Poirot","_prénom":"Hercule","_âge":66,"_discipline":"détective"}
enseignant= {"_nom":"Poirot","_prénom":"Hercule","_âge":66,"_discipline":"détective"}
paramètre= {"_nom":"Marple","_prénom":"Miss","_âge":70} object
personne= {"_nom":"Marple","_prénom":"Miss","_âge":70}
  • righe 4 e 6: Javascript riconosce correttamente il tipo delle istanze di classe;