Kurs obiektowego JavaScript (26)

Autor: Damian Chodorek • Opublikowany: 17 października 2014 • Ostatnia aktualizacja: 8 lutego 2015 • Kategoria: javascript, kursy

Dostęp do klasy nadrzędnej. Więcej sposobów dziedziczenia.

W popularnych językach obiektowych istnieje możliwość wywołania pól i metod należących do klasy bazowej. W JS oczywiście nie ma bezpośredniego sposobu, ale da się to łatwo zaimplementować. Słowem kluczowym uczynimy uber, które z niemieckiego oznacza nad. Dlaczego nie super? Ponieważ to słowo już jest zarezerwowane w JS.

function A(){}
A.prototype.name="A";
A.prototype.getName=function(){
  var result=[];
  if(this.constructor.uber){
    //dolepmy nazwy z całego łańcucha dziedziczenia
    result.push( this.constructor.uber.getName() );
  }
  result.push(this.name);
  return result.join(', ');
};

function B(){}
var F=function(){};
F.prototype=A.prototype;
B.prototype=new F();
B.prototype.constructor=B;
B.uber=A.prototype; //pole dające dostęp do rodzica
B.prototype.name="B";

function C(){}
var F=function(){};
F.prototype=B.prototype;
C.prototype=new F();
C.prototype.constructor=C;
C.uber=B.prototype; //pole dające dostęp do rodzica
C.prototype.name="C";

//zobacz jak teraz działa getName()
var c=new C();
c.getName(); //"A, B, C"

Dziedziczenie przy pomocy funkcji

Być może zauważyłeś, że dziedziczenie wymaga wykonania kilku powtarzających się czynności. Rozsądnym więc byłoby zawarcie procesu dziedziczenia w osobnej funkcji. Zwiększy to czytelność kodu, zaoszczędzi pisania i zmniejszy prawdopodobieństwo pomyłek. Funkcję nazwiemy na cześć słówka kluczowego z języka Java – extend.

function extend(Child, Parent){
  var F=function(){};
  F.prototype=Parent.prototype;
  Child.prototype=new F();
  Child.prototype.constructor=Child;
  Child.uber=Parent.prototype;
}

function A(){};
A.prototype.name="A";

function B(){};

extend(B,A);

B.prototype.name="B";

var b=new B();
b.name; //"B"
b.constructor.uber.name; //"A" - uber siedzi w konstruktorze

Dziedziczenie poprzez kopiowanie obiektów

Czym jest dziedziczenie? To ponowne wykorzystanie kodu. Do tej pory dowiedziałeś się jak wykonać operację dziedziczenia przy użyciu prototypów. Jest jednak prostszy i również popularny sposób. Można po prostu skopiować odpowiednie pola z rodzica do dziecka. To wszystko! Trzeba jednak pamiętać, aby była to kopia głęboka, czyli taka, która kopiuje obiekty, a nie referencje.

Poniżej przedstawiam funkcję deepCopy(). Zwraca ona kopię obiektu. Jeśli dane pole jest typu Object, to wykonywane jest jego całkowite kopiowanie. Taki sposób dziedziczenia będzie działał odrobinę mniej wydajnie. Niemniej jest często stosowany. Przykładowo w nowych wersjach popularnej biblioteki jQuery.

Ideologia tej metody dziedziczenia będzie trochę inna niż poznanej już funkcji extend(). Pomijamy prototypy i konstruktory. Wykonujemy zwykłą kopię obiektu rodzica, a potem rozszerzamy jej funkcjonalność.

function deepCopy(p, b){
  var c=b || {}; //bazą dla obiektu kopii będzie pusty obiekt lub jakiś inny
  for( var i in p ){
    if( typeof p[i]==="object" ){ //jeśli pole jest obiektem
      if( p[i].constructor===Array ) //jeśli pole jest tablicą
        c[i]=[]; //to przypisz pustą tablicę do c[i]
      else //jeśli nie
        c[i]={}; //przypisz zwykły obiekt
      deepCopy( p[i],c[i] ); //wywołaj rekurencyjnie funkcję dla pola
    }else //jeśli pole jest typem prostym
    {
       c[i]=p[i]; //typy proste kopiowane są przez wartość
    }
  }
  return c;
}

//przykład zastosowania:
var parent={  //obiekt rodzica
  arr: ['a', 'b', 'c'], // posiada tablicę
  inObj: { val: 1 },    // posiada obiekt
  bool: true            // posiada typ prosty
}

var child=deepCopy(parent); //przekażemy jeden parametr więc drugi przyjmie wartość "undefined"

child.arr[0]=123;
child.inObj.val=0;
child; //Object {arr: Array[3], inObj: Object, bool: true}
child.inObj; //Object {val: 0}
child.arr; //[123, "b", "c"]

parent.arr; //['a', 'b', 'c'] 
parent.inObj; //Object {val: 1}  
/*obiekt nadrzędny jest ciągle taki sam, to znaczy, że kopia wykonała się poprawnie*/

Zauważ, że ta metoda pozwala na bezpośrednie dziedziczenie obiektów. Nie ma tutaj mowy o konstruktorach.

Jeszcze jeden sposób na dziedziczenie

Skorzystamy z nowego podejścia – funkcji, która przyjmuje i zwraca obiekt. Tym razem sposób nie będzie oparty o kopię, ale o prototyp.

function object(o){
  var n;
  function F(){};
  F.prototype=o;
  n=new F();
  n.uber=o;

  return n;
}

var parent={
  name: "parent",
  getName: function(){ return this.name; }
}

var child=object(parent);

child.name="child";
child.getName(); //"child"
child.uber.name; //"parent"

parent.name; //"parent"

Widzimy więc, że wszystko działa jak należy.

Wielokrotne dziedziczenie

Z lektury dzisiejszego posta być może domyślasz się jak można je zaimplementować. Można przykładowo skopiować pola wielu obiektów do docelowego.

W tym artykule to wszystko. Przejdź do następnej części:

Kurs obiektowego JavaScript (27)

Zobacz również
Kurs obiektowego JavaScript (24)Rozszerzanie funkcjonalności obiektów wbudowanych.
Kurs obiektowego JavaScript (25)Wstęp do dziedziczenia w JS.
Kurs obiektowego JavaScript (27)Jak dołączyć kod JS do strony HTML? Poznaj modele BOM i DOM.
Kurs obiektowego JavaScript (28)Dokładniejsze omówienie modelu BOM. Obiekt window.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.