Myślenie w JS-ie klasycznie zamiast prototypowo może się okazać Złym Pomysłem. JS jest na tyle elastyczny, że można w nim zaimplementować klasyczne dziedziczenie, ale naturalnie jest prototypowy. Obiekty dziedziczą tu po obiektach. Nie ma dodatkowych bytów zwanych "klasami". W JS-ie jest więc -- obiektywnie rzecz biorąc -- prościej, ze względu na mniejszą liczbę bytów, ale ponieważ języki z dziedziczeniem klasycznym są powszechniejsze, przestawienie się na prototypowość sprawia problemy.
Minusem JS-a jest też to, że udaje nieco Javę tym strasznym słówkiem new
. Ten operator jest bardzo nieużyteczny. Dokonuje dziedziczenia prototypowego w bardzo niewygodny sposób. Lepiej już użyć Object.create(proto)
, które tworzy nowy, pusty obiekt, dziedziczący po proto
.
Używając prototypów i nie pisząc żadnych funkcji pomocniczych (które IMO są praktycznie niezbędne jeśli ma to pseudo-klasyczne dziedziczenie jakoś wyglądać), Twój przykład można pociągnąć dalej tak...
var Base = function(var1) {
this.var1 = var1;
this.var2 = var2;
};
Base.prototype.getX = function() {
return this.var1;
};
var Derived = function(var1, var3) {
Base.call(this, var1);
this.var3 = var3;
this.var4 = 8;
};
Derived.prototype = new Base(); // niezgrabne: odpalamy konstruktor nie podając mu parametrów...
Derived.prototype.getX = function() {
return Base.prototype.getX.call(this) + this.var4; // niezgrabne, to powinno być wyabstrahowane do jakiejś funkcji super()/uber()
};
Przyznam, że nie testowałem tego zbyt dokładnie, ale powinno to być mniej więcej coś takiego. Bez funkcji pomocnicznych jest niezbyt zgrabnie, ale spróbuj na tych zasadach zaimplementować w Javie dziedziczenie prototypowe!
Inna obiektowość, bardziej funkcyjna, z prawdziwą hermetyzacją (powyżej, wszystkie składowe są de facto publiczne):
function createBase(var1) {
var var2 = 6;
var self = {};
self.getX = function() {
return var1;
};
return self;
}
function createDerived(var1, var3) {
var var4 = 8;
var self = createBase(var1);
var superGetX = self.getX;
self.getX = function() {
return superGetX() + var4;
};
return self;
};
Minusem powyższego rozwiązania jest większy koszt tworzenia obiektów niż w przypadku dziedziczenia prototypowego. Ale to rzadko jest problemem, bo w JS-ie rzadko mamy duże grupy obiektów.
W JS-ie generalnie nie tworzy się głębokich hierarchii dziedziczenia. "Nadtypów" jest przeważnie 1, 2. Zwykle nie ma takiej potrzeby, choć trzeba się przestawić.
DRY zachowuje się dzięki funkcyjności. Można prosto tworzyć mixiny.
Pamiętaj, że tu nie ma statycznej kontroli typów. W JS-ie musisz polegać na testach automatycznych. Które i tak wypada pisać, prawda? ;)