METODI STATICI
Possiamo anche assegnare metodi alle classi stesse, non solamente al loro “prototype”. Questi metodi sono detti statici. All’interno della classe, questi vengono preceduti dalla keyword static, come possiamo vedere nell’esempio:
class User {
static staticMethod() {
alert(this === User);
}
}
User.staticMethod(); // true
Il valore di this nella chiamata User.staticMethod() è rappresentato dal costruttore della classe User (la regola dell’oggetto prima del punto). Solitamente, i metodi statici vengono utilizzati per rappresentare funzioni che appartengono alla classe, ma non ad un oggetto in particolare. Ad esempio, potremmo avere degli oggetti di tipo Article e necessitare di una funzione per confrontarli. Una soluzione naturale sarebbe quella di aggiungere il metodo Article.compare, come nell’esempio:
class Article {
constructor(title, date) {
this.title = title;
this.date = date;
}
static compare(articleA, articleB) {
return articleA.date – articleB.date;
}
}
// usage
let articles = [
new Article(“HTML”, new Date(2019, 1, 1)),
new Article(“CSS”, new Date(2019, 0, 1)),
new Article(“JavaScript”, new Date(2019, 11, 1))
];
articles.sort(Article.compare);
alert( articles[0].title ); // CSS
Qui Article.compare sta “al di sopra” degli articoli, poiché ha lo scopo di confrontarli. Non è un metodo di un articolo, ma piuttosto dell’intera classe. Un altro esempio comune è quello del “factory method” (un particolare design pattern). Immaginiamo di avere bisogno di diverse modalità di creazione di un articolo:
- Creazione con i parametri forniti (title, date etc).
- Creazione di un articolo vuoto con la data di oggi.
- …o qualsiasi altra modalità.
Il primo metodo può essere implementato tramite il costruttore. Mentre per il secondo, possiamo creare un metodo statico appartenente alla classe.
Come Article.createTodays() nell’esempio:
class Article {
constructor(title, date) {
this.title = title;
this.date = date;
}
static createTodays() {
// ricorda, this = Article
return new this(“Today’s digest”, new Date());
}
}
let article = Article.createTodays();
alert( article.title ); // Today’s digest
Ora, ogni volta in cui avremo bisogno di creare un “today’s digest”, possiamo invocare Article.createTodays(). Ripetiamolo nuovamente, questo non è un metodo per uno specifico articolo, ma piuttosto un metodo dell’intera classe. I metodi di classe statici sono definiti sulla classe stessa. Non puoi chiamare un metodo statico su un oggetto, solo su una classe di oggetti.
class Car {
constructor(name) {
this.name = name;
}
static hello() {
return “Hello!!”;
}
}
let myCar = new Car(“Ford”);
// You can call ‘hello()’ on the Car Class:
document.getElementById(“demo”).innerHTML = Car.hello();
// But NOT on a Car Object:
// document.getElementById(“demo”).innerHTML = myCar.hello();
// this will raise an error.
Se vuoi utilizzare l’oggetto myCar all’interno del metodo statico, puoi inviarlo come parametro:
class Car {
constructor(name) {
this.name = name;
}
static hello(x) {
return “Hello “ + x.name;
}
}
let myCar = new Car(“Ford”);
document.getElementById(“demo”).innerHTML = Car.hello(myCar);
PROPRIETA’ STATICHE
È anche possibile definire proprietà statiche, queste sono molto simili alle proprietà della classe, ma sono precedute dalla keyword static:
class Article {
static publisher = “Ilya Kantor”;
}
alert( Article.publisher ); // Ilya Kantor
EREDITARIETA’ DEI METODI E DELLE PROPRIETA’ STATICHE
Anche le proprietà ed i metodi statici vengono ereditati. Ad esempio, Animal.compare e Animal.planet nel codice sotto, vengono ereditate e diventano quindi accessibili come Rabbit.compare e Rabbit.planet:
class Animal {
static planet = “Earth”;
constructor(name, speed) {
this.speed = speed;
this.name = name;
}
run(speed = 0) {
this.speed += speed;
alert(`${this.name} runs with speed ${this.speed}.`);
}
static compare(animalA, animalB) {
return animalA.speed – animalB.speed;
}
}
// Eredita da Animal
class Rabbit extends Animal {
hide() {
alert(`${this.name} hides!`);
}
}
let rabbits = [
new Rabbit(“White Rabbit”, 10),
new Rabbit(“Black Rabbit”, 5)
];
rabbits.sort(Rabbit.compare);
rabbits[0].run(); // Black Rabbit runs with speed 5.
alert(Rabbit.planet); // Earth
Ora, quando invochiamo Rabbit.compare, verrà invocato il metodo Animal.compare ereditato.
Come funziona? Nuovamente, utilizzando il prototypes. Come potrete aver già intuito, extends fornisce a Rabbit il riferimento a [[Prototype]] di Animal.
- La funzione Rabbit eredita dalla funzione di Animal.
- prototype eredita il prototype di Animal.prototype.
Come risultato, l’ereditarietà funziona sia per i metodi regolari che per quelli statici.
Ora, verifichiamo quanto detto guardando al codice:
class Animal {}
class Rabbit extends Animal {}
// per proprietà statiche
alert(Rabbit.__proto__ === Animal); // true
// per proprietà regolari
alert(Rabbit.prototype.__proto__ === Animal.prototype); // true
Scrivi un commento