Arv
Arv är den process genom vilken ett objekt kan baseras på ett annat. Detta gör att objekten kan dela varandras egenskaper.
Jag har skapat prototypen Hero
och använt den för att skapa ett nytt objekt som heter superman
. Men vi gör ingenting med detta objekt. Så låt oss ta hand om det genom att skapa en annan funktion som heter dialogue
.
function dialogue() {
console.log('I am ' + this.name);
}
Men om vi kör vår kod nu kommer ingenting att hända eftersom den här funktionen inte vet vad namnet egentligen är. För detta måste vi
Jag vill att denna nya funktion ska ha samma egenskaper som Hero
. Istället för att skriva ner dem inne i den här funktionen kan vi helt enkelt be JavaScript att ärva dem från Hero
-prototypen.
Detta är möjligt med hjälp av prototype
-egenskapen som är tillgänglig inom alla objekt i JavaScript.
Då vi placerar dialogue
på Hero.prototype
har vi gjort den tillgänglig för alla instanser av Hero
.
Differentiell arv
JavaScript har också en annan arvsmodell som kallas ”differentiell arv”. I denna modell kopieras inte metoderna från föräldern till barnet. Utan istället finns det en länk mellan barnen och deras föräldraobjekt.
Här har superman
faktiskt inte en egen metod som heter dialogue()
. Men hur fungerar då superman.dialogue()
?
När JavaScript-motorn stöter på superman.dialogue()
i koden letar den efter egenskapen dialogue
i superman
-objektet. När den inte hittar en sådan letar den uppåt i prototypkedjan till superman
s överordnade Hero.prototype
. Där hittar den Hero.prototype.dialogue
och anropar den med en this
som är bunden till superman
.
Object.create()
Vi kan göra detta ännu mer exklusivt genom att skapa en ny klass för Superman
som kommer att ärva egenskaperna i Hero
s prototyp. Vi kan göra detta genom att tilldela Superman
s prototyp till Hero
s prototyp så här:
function Superman() {}
Superman.prototype = Hero.prototype
Men vad detta gör är att det bara gör både och Hero
lika. Vad vi egentligen behöver är ett nytt objekt som är baserat på prototypen Hero
. Sedan ES5 har JavaScript en inbyggd funktion som heter Object.create()
. Låt oss använda den här som visas nedan:
Superman.prototype = Object.create(Hero.prototype);
Detta kommer att skapa ett nytt tomt objekt som är baserat på prototypen Hero
och tilldela det till prototypen Superman
. Så alla egenskaper som vi har i Hero
-prototypen kan nu nås av Superman
-prototypen. Så istället för att ringa new Hero
kan vi ringa new Superman
och allt kommer fortfarande att fungera som det ska.
Men om du tittar närmare på resultatet kommer du att märka att det finns en undefined
inuti det. Det beror på att Hero
för närvarande bara är en konstruktör för sig själv. Vi måste call
egenskaperna hos Hero
inuti Superman
prototypen.
function Superman() {
Hero.call(this, 'Superman', 'Clark Kent', 'Krypton')
}
Låt oss skapa en annan konstruktör som heter MarvelMovies
som visas nedan:
function MarvelMovies(movieName, releaseYear) {
this.movieName = movieName;
this.releaseYear = releaseYear;
}
När en funktion används som konstruktör hänvisar this
till det nya objektet som vi skapar. I den här konstruktören har jag alltså tagit movieName
och releaseYear
som argument och tilldelat dessa värden till egenskaperna movieName
och releaseYear
för vår nya MarvelMovies
instans som heter avengers
.
var avengers = new MarvelMovies("avengers", 2012);
Jag kommer sedan att skapa en ny metod som heter output
för denna prototyp som visas nedan:
MarvelMovies.prototype.output = function() {
return "Movie: " + this.movieName + " Released in " + this.releaseYear;
}
console.log(avengers.output());
Framtida arv
En riktigt bra aspekt av arv är att JavaScript låter dig ändra eller utöka funktionerna i en klass även efter att du har definierat den.
JavaScript kommer att slå upp prototypen när du försöker få tillgång till egenskaperna på ett objekt. Du kan alltså ändra klasser vid körning!
För att illustrera detta kan vi skapa en array enligt nedan:
var numbers = ;
Array.prototype.shuffle = function() {
return this.sort(function() {
return Math.round( Math.random() * 2) - 1;
});
};
console.log(numbers.shuffle());
Här fanns arrayen numbers
redan innan arrayen Array.prototype.shuffle
fanns. Men i JavaScript går egenskapsökningarna uppåt i prototypkedjan. Därför får arrayen fortfarande tillgång till den nya metoden shuffle
, eftersom den finns på Array.prototype
när vi faktiskt försöker använda den.
Enklare uttryckt skapade vi en array, gick sedan tillbaka och gav alla Arrays tillgång till en ny metod.