
W pierwszej części pokazującej dziedziczenie w JavaScript, pokazałem tzw. podejście “klasyczne”, mające niby być najbardziej zbliżonym do tego, spotykanego w językach programowania posiadających silne typowanie. Tamten wpis wywołał pewne kontrowersje… Być może nie do końca dobrze wszystko wyjaśniłem, a może to ja się mylę ;) Nie jestem alfą i omegą… Jednak zostawmy już w spokoju podejście “classic” ponieważ jest ono mało szczęśliwe i najlepiej jest go w ogóle nie używać. Lepszym rozwiązaniem jest zapoznanie się i zrozumienie tego co pokażę dzisiaj! W dzisiejszym wpisie zajmiemy się bowiem czymś co znane jest pon nazwą “pożyczanie konstruktora”.

#2 Dziedziczenie w JavaScript - pożyczanie konstruktora
W pierwszej części pokazującej dziedziczenie w JavaScript, pokazałem tzw. podejście “klasyczne”, mające niby być najbardziej zbliżonym do tego, spotykanego w językach programowania posiadających silne typowanie. Tamten wpis wywołał pewne kontrowersje… Być może nie do końca dobrze wszystko wyjaśniłem, a może to ja się mylę ;) Nie jestem alfą i omegą… Jednak zostawmy już w spokoju podejście “classic” ponieważ jest ono mało szczęśliwe i najlepiej jest go w ogóle nie używać. Lepszym rozwiązaniem jest zapoznanie się i zrozumienie tego co pokażę dzisiaj! W dzisiejszym wpisie zajmiemy się bowiem czymś co znane jest pon nazwą “pożyczanie konstruktora”.
Pożyczanie konstruktora + ustawianie prototypu
Uważam, że pokazywana dziś przeze mnie technika jest dużo łatwiejsza do zrozumienia niż poprzednio pokazywany przypadek. Przede wszystkim nie stosujemy słowa kluczowego new
, więc nic nie dzieje się “automagicznie” gdzieś pod spodem. Może zacznijmy od krótkiego wyjaśnienia pierwszej części tego sposobu dziedziczenia czyli pożyczania konstruktora. Oto przykładowa funkcja rodzic:
function Parent (firstName) {
this.firstName = firstName;
}
Parent.prototype.getFirstName = function () {
return this.firstName;
}
Na razie nic nowego - zwykła funkcja oraz dodanie funkcji do jej prototypu. Wszystko zmienia się kiedy spojrzymy na funkcję dziecka, która pożycza konstruktor:
function Child (firstName, lastName) {
// call parent constructor
Parent.call(this, firstName);
this.lastName = lastName;
}
Warto zwrócić uwagę, na zaznaczoną linię numer trzy. Jest to nic innego jak jawne wywołanie funkcji (konstruktora) Parent
w kontekście funkcji Child
(przekazanie this
jako pierwszego parametru). Utwórzmy teraz obiekt za pomocą konstruktora Child
i słowa kluczowego new
(czyli w stylu “klasycznym”) oraz sprawdźmy kilka rzeczy.
var child = new Child('Henryk', 'Malinowski');
alert(child.firstName);
alert(child.lastName);
alert(typeof child.getFirstName); // undefined
Jak widać, obiekt child
posiada teraz zarówno odziedziczoną właściwość firstName
oraz swoją własną właściwość lastName
, czyli uzyskaliśmy pożądany efekt. Tutaj jedna uwaga: wywołanie call
z poprzedniego przykładu spowodowało skopiowanie - właściwość firstName
jest kopią a nie referencją więc nie ma ryzyka nadpisania wartości zapisanych we właściwościach rodzica! Wadą tego rozwiązania jest zaś zupełny brak dziedziczenia prototypu obiektu co jest przecież podstawą dziedziczenia w JavaScript - widać to doskonale w ostatniej zaznaczonej linii gdzie sprawdzenie typu funkcji child.getFirstName
zwraca wartość undefined
.
Jest jednak oczywiście sposób by temu zaradzić. Wystarczy do naszego kodu dodać jedną linię (przed wywołaniem konstruktora dziecka):
Child.prototype = new Parent();
lub lepiej:
Child.prototype = Object.create(Parent.prototype);
W ten sposób zapewniamy sobie przypisanie prototypowi dziecka obiektu prototypu rodzica (za pomocą Object.create
, o której będzie jeszcze mowa w kolejnych częściach cyklu o dziedziczeniu). W tym momencie ostatnia linia z poprzedniego przykładu zacznie zwracać wartość function
.
Podsumowanie
Na zakończenie oczywiście codepen, abyście mogli empirycznie sprawdzić, że to faktycznie działa:
See the Pen azGRJP by burczu (@burczu) on CodePen.
Pożyczanie konstruktora to najpopularniejszy sposób na dziedziczenie w JavaScript. W przedstawionym podejściu dziedziczone są zarówno właściwości prototypu obiektu rodzica jak i jego własne właściwości ustawione w konstruktorze z użyciem słowa kluczowego this
. Należałoby się zastanowić czy to na pewno dobre podejście? Ale o tym w jednym z kolejnych wpisów.