Dziedziczenie
Dziedziczenie jest procesem, przez który jeden obiekt może być oparty na innym. Pozwala to obiektom dzielić wzajemnie swoje właściwości.
Utworzyłem prototyp Hero
i użyłem go do utworzenia nowego obiektu o nazwie superman
. Ale my nic nie robimy z tym obiektem. Zajmijmy się więc tym, tworząc kolejną funkcję o nazwie dialogue
.
function dialogue() {
console.log('I am ' + this.name);
}
Ale jeśli teraz uruchomimy nasz kod, nic się nie stanie, ponieważ ta funkcja nie wie, jaka naprawdę jest nazwa. W tym celu musimy
Chcę, aby ta nowa funkcja miała te same właściwości, co funkcja Hero
. Zamiast zapisywać je wewnątrz tej funkcji, możemy po prostu powiedzieć JavaScriptowi, aby odziedziczył je z prototypu Hero
.
Jest to możliwe za pomocą właściwości prototype
, która jest dostępna wewnątrz każdego obiektu w JavaScript.
Przez umieszczenie dialogue
na Hero.prototype
, udostępniliśmy ją wszystkim instancjom Hero
.
Dyfferencyjne dziedziczenie
JavaScript posiada również inny model dziedziczenia zwany „dziedziczeniem różnicowym”. W tym modelu, metody nie są kopiowane z rodzica do dziecka. Ale zamiast tego istnieje związek między dziećmi i ich obiektem nadrzędnym.
Tutaj, superman
w rzeczywistości nie ma swojej własnej metody o nazwie dialogue()
. Ale w takim razie jak działa superman.dialogue()
?
Kiedy silnik JavaScript natrafia w kodzie na superman.dialogue()
, szuka właściwości o nazwie dialogue
wewnątrz obiektu superman
. Gdy jej nie znajdzie, zajrzy w górę łańcucha prototypów do rodzica superman
Hero.prototype
. Tam znajdzie Hero.prototype.dialogue
i wywoła go za pomocą this
, który jest związany z superman
.
Object.create()
Możemy uczynić to jeszcze bardziej ekskluzywnym, tworząc nową klasę dla Superman
, która będzie dziedziczyć właściwości prototypu Hero
. Możemy to zrobić przypisując prototyp Superman
do prototypu Hero
w ten sposób:
function Superman() {}
Superman.prototype = Hero.prototype
Ale to, co to robi, to po prostu czyni oba Superman
i Hero
równymi. To, czego naprawdę potrzebujemy, to nowy obiekt, który jest oparty na prototypie Hero
. Od ES5, JavaScript posiada wbudowaną funkcję o nazwie Object.create()
. Użyjmy jej tutaj, jak pokazano poniżej:
Superman.prototype = Object.create(Hero.prototype);
To stworzy nowy pusty obiekt, który jest oparty na prototypie Hero
i przypisze go do prototypu Superman
. Tak więc wszystkie właściwości, które mamy w prototypie Hero
mogą być teraz dostępne dla prototypu Superman
. Zamiast więc wywoływać new Hero
, możemy wywołać new Superman
i wszystko nadal będzie działać tak, jak powinno.
Jeśli jednak przyjrzysz się dokładniej danym wyjściowym, zauważysz, że w środku znajduje się undefined
. Dzieje się tak dlatego, że obecnie Hero
jest konstruktorem tylko dla siebie. Musimy call
właściwości Hero
wewnątrz Superman
prototypu.
function Superman() {
Hero.call(this, 'Superman', 'Clark Kent', 'Krypton')
}
Utwórzmy kolejny konstruktor o nazwie MarvelMovies
, jak pokazano poniżej:
function MarvelMovies(movieName, releaseYear) {
this.movieName = movieName;
this.releaseYear = releaseYear;
}
Gdy funkcja jest używana jako konstruktor, this
odnosi się do nowego obiektu, który tworzymy. Tak więc w tym konstruktorze, wziąłem movieName
i releaseYear
jako argumenty i przypisałem te wartości do właściwości movieName
i releaseYear
naszej nowej instancji MarvelMovies
o nazwie avengers
.
var avengers = new MarvelMovies("avengers", 2012);
Następnie utworzę nową metodę o nazwie output
dla tego prototypu, jak pokazano poniżej:
MarvelMovies.prototype.output = function() {
return "Movie: " + this.movieName + " Released in " + this.releaseYear;
}
console.log(avengers.output());
Przyszłe dziedziczenie
Naprawdę wspaniałym aspektem dziedziczenia jest to, że JavaScript pozwala ci modyfikować lub rozszerzać właściwości klasy nawet po jej zdefiniowaniu.
JavaScript będzie szukał prototypu przy próbie dostępu do właściwości obiektu. Tak więc, możesz zmieniać klasy w czasie wykonywania!
Aby to zilustrować, utwórzmy tablicę, jak pokazano poniżej:
var numbers = ;
Array.prototype.shuffle = function() {
return this.sort(function() {
return Math.round( Math.random() * 2) - 1;
});
};
console.log(numbers.shuffle());
Tutaj, tablica numbers
istniała przed tablicą Array.prototype.shuffle
. Ale w JavaScript, wyszukiwania właściwości idą w górę łańcucha prototypów. To dlatego tablica wciąż uzyskuje dostęp do nowej metody shuffle
, ponieważ istnieje na Array.prototype
, gdy faktycznie próbujemy jej użyć.
W prostych słowach, stworzyliśmy tablicę, a następnie cofnęliśmy się i daliśmy wszystkim tablicom dostęp do nowej metody.