Ereditarietà
L’ereditarietà è il processo con cui un oggetto può essere basato su un altro. Questo permette agli oggetti di condividere le proprietà dell’altro.
Ho creato il prototipo Hero
e l’ho usato per creare un nuovo oggetto chiamato superman
. Ma non stiamo facendo nulla con questo oggetto. Quindi occupiamoci di questo creando un’altra funzione chiamata dialogue
.
function dialogue() {
console.log('I am ' + this.name);
}
Ma se ora eseguiamo il nostro codice, non succederà nulla perché questa funzione non sa qual è il nome reale. Per questo, abbiamo bisogno di
Voglio che questa nuova funzione abbia le stesse proprietà di quella Hero
. Invece di scriverle all’interno di questa funzione, possiamo semplicemente dire a JavaScript di ereditarle dal prototipo Hero
.
Questo è possibile con l’aiuto della proprietà prototype
che è disponibile in qualsiasi oggetto in JavaScript.
Mettendo dialogue
su Hero.prototype
, lo abbiamo reso disponibile a tutte le istanze di Hero
.
Eredità differenziale
JavaScript ha anche un altro modello di eredità chiamato “eredità differenziale”. In questo modello, i metodi non sono copiati dal genitore al figlio. Ma invece c’è un legame tra i figli e il loro oggetto genitore.
Qui, superman
in realtà non ha un suo metodo chiamato dialogue()
. Ma allora come funziona superman.dialogue()
?
Quando il motore JavaScript incontra superman.dialogue()
nel codice, cerca la proprietà chiamata dialogue
dentro l’oggetto superman
. Quando non ne trova una, cercherà nella catena dei prototipi il genitore Hero.prototype
di superman
. Lì troverà Hero.prototype.dialogue
e lo chiamerà con un this
che è legato a superman
.
Object.create()
Possiamo rendere questo ancora più esclusivo creando una nuova classe per Superman
che erediterà le proprietà del prototipo Hero
. Possiamo farlo assegnando il prototipo di Superman
al prototipo di Hero
in questo modo:
function Superman() {}
Superman.prototype = Hero.prototype
Ma questo non fa altro che rendere uguali sia Superman
che Hero
. Quello di cui abbiamo veramente bisogno è un nuovo oggetto che sia basato sul prototipo Hero
. Da ES5, JavaScript ha una funzione integrata chiamata Object.create()
. Usiamola qui come mostrato qui sotto:
Superman.prototype = Object.create(Hero.prototype);
Questo creerà un nuovo oggetto vuoto che è basato sul prototipo Hero
e lo assegnerà al prototipo Superman
. Così tutte le proprietà che abbiamo nel prototipo Hero
possono ora essere accessibili dal prototipo Superman
. Quindi invece di chiamare new Hero
, possiamo chiamare new Superman
e tutto funzionerà ancora come dovrebbe.
Ma se guardate più da vicino l’output, noterete che c’è un undefined
al suo interno. Questo perché attualmente il Hero
è un costruttore solo per se stesso. Dobbiamo call
le proprietà di Hero
all’interno del Superman
prototipo.
function Superman() {
Hero.call(this, 'Superman', 'Clark Kent', 'Krypton')
}
Creiamo un altro costruttore chiamato MarvelMovies
come mostrato qui sotto:
function MarvelMovies(movieName, releaseYear) {
this.movieName = movieName;
this.releaseYear = releaseYear;
}
Quando una funzione è usata come costruttore, this
si riferisce al nuovo oggetto che stiamo creando. Così in questo costruttore, ho preso movieName
e releaseYear
come argomenti e ho assegnato questi valori alle proprietà movieName
e releaseYear
della nostra nuova istanza MarvelMovies
chiamata avengers
.
var avengers = new MarvelMovies("avengers", 2012);
Creerò poi un nuovo metodo chiamato output
per questo prototipo come mostrato qui sotto:
MarvelMovies.prototype.output = function() {
return "Movie: " + this.movieName + " Released in " + this.releaseYear;
}
console.log(avengers.output());
Eredità futura
Un aspetto davvero fantastico dell’ereditarietà è che JavaScript vi permette di modificare o espandere le caratteristiche di una classe anche dopo averla definita.
JavaScript cercherà il prototipo quando si cerca di accedere alle proprietà di un oggetto. Quindi, potete alterare le classi in fase di esecuzione!
Per illustrare questo, creiamo un array come mostrato qui sotto:
var numbers = ;
Array.prototype.shuffle = function() {
return this.sort(function() {
return Math.round( Math.random() * 2) - 1;
});
};
console.log(numbers.shuffle());
Qui, l’array numbers
esisteva prima di quello Array.prototype.shuffle
. Ma in JavaScript, le ricerche delle proprietà risalgono la catena dei prototipi. Questo è il motivo per cui l’array ha ancora accesso al nuovo metodo shuffle
, poiché esiste sul Array.prototype
quando stiamo effettivamente cercando di usarlo.
In termini semplici, abbiamo creato un array, poi siamo tornati indietro e abbiamo dato a tutti gli array l’accesso a un nuovo metodo.