[ Pobierz całość w formacie PDF ]
} Rectangle.prototype.inheritFrom(Polygon); Rectangle.prototype.getArea = function () { return this.iLength * this.iWidth; }; Aby przetestować ten kod, możemy posłużyć się tym samym przykładem co wcześniej, do- dając kilka dodatkowych wierszy testujących metodę instanceOf(): var oTriangle = new Triangle(12, 4); var oRectangle = new Rectangle(22, 10); alert(oTriangle.iSides); alert(oTriangle.getArea()); alert(oRectangle.iSides); alert(oRectangle.getArea()); alert(oTriangle.instanceOf(Triangle)); // wyświetla "true" alert(oTriangle.instanceOf(Polygon)); // wyświetla "true" alert(oRectangle.instanceOf(Rectangle)); // wyświetla "true" alert(oRectangle.instanceOf(Polygon)); // wyświetla "true" Ostatnie cztery wiersze testują metodę instanceOf() i w każdym przypadku powinny zwrócić true. 144 JavaScript. Zaawansowane programowanie Obsługa metody prototypów dynamicznych Jak już wspomniano, wiązania łańcuchowego prototypów nie da się zastosować z zachowa- niem ducha metody prototypów dynamicznych, który sprowadza się do utrzymaniu całego kodu klasy w obrębie konstruktora. Biblioteka zInherit poprawia ten problem, umożliwiając wywoływanie metody inheritFrom() z wnętrza konstruktora. Spójrzmy na użyty wcześniej przykład klas wielokątów zapisanych metodą prototypów dy- namicznych, tym razem uzupełniony o możliwości biblioteki zInherit: function Polygon(iSides) { this.iSides = iSides; if (typeof Polygon._initialized == "undefined") { Polygon.prototype.getArea = function() { return 0; }; Polygon._initialized = true; } } function Triangle(iBase, iHeight) { Polygon.call(this, 3); this.iBase = iBase; this.iHeight = iHeight; if (typeof Triangle._initialized == "undefined") { Triangle.prototype.inheritFrom(Polygon); Triangle.prototype.getArea = function() { return 0.5 * this.iBase * this.iHeight; }; Triangle._initialized = true; } } function Rectangle(iLength, iWidth) { Polygon.call(this, 4); this.iLength = iLength; this.iWidth = iWidth; if (typeof Rectangle._initialized == "undefined") { Rectangle.prototype.inheritFrom(Polygon); Rectangle.prototype.getArea = function () { return this.iLength * this.iWidth; }; Rectangle._initialized = true; } } Rozdział 4. Dziedziczenie 145 Dwa wyróżnione wiersze w powyższym kodzie implementują dziedziczenie klasy Polygon dla dwóch potomków klas Triangle i Rectangle. Kod działa, ponieważ tym razem obiekt prototype nie został nadpisany, co wynika z zastosowania metody inheritFrom(). Dodano do niego tylko metody. Tym sposobem możliwe jest ominięcie ograniczeń wiąza- nia łańcuchowego prototypów i zaimplementowanie prototypów dynamiczne zgodnie z du- chem tego wzorca. Obsługa wielokrotnego dziedziczenia Jedną z najbardziej przydatnych możliwości biblioteki zInherit jest obsługa dziedziczenia wielokrotnego, które nie jest dostępne przy stosowaniu wiązania łańcuchowego prototypów. Ponownie kluczowym czynnikiem, który to umożliwia, jest to, że inheritFrom() nie zastę- puje obiektu prototype. Aby dziedziczyć metody i właściwości, metoda inheritFrom() musi zostać użyta w powiąza- niu z maskowaniem obiektów. Wezmy następujący przykład: function ClassX() { this.sMessageX = "To jest komunikat X."; if (typeof ClassX._initialized == "undefined") { ClassX.prototype.sayMessageX = function() { alert(this.sMessageX); }; ClassX._initialized = true; } } function ClassY() { this.sMessageY = "To jest komunikat Y."; if (typeof ClassY._initialized == "undefined") { ClassY.prototype.sayMessageY = function () { alert(this.sMessageY); }; ClassY._initialized = true; } } ClassX i ClassY to małe klasy z jedną właściwością i jedną metodą. Powiedzmy, że stwo- rzyliśmy klasę ClassZ, która ma być potomkiem obu tych klas. Klasę tą można zdefiniować następująco: function ClassZ() { ClassX.apply(this); ClassY.apply(this); this.sMessageZ = "To jest komunikat Z."; if (typeof ClassZ._initialized == "undefined") { 146 JavaScript. Zaawansowane programowanie ClassZ.prototype.inheritFrom(ClassX); ClassZ.prototype.inheritFrom(ClassY); ClassZ.prototype.sayMessageZ = function () { alert(this.sMessageZ); }; ClassZ._initialized = true; } } Zwróćmy uwagę, że pierwsze dwa wyróżnione wiersze dziedziczą właściwości (metodą apply()), a dwa kolejne wyróżnione wiersze dziedziczą metody (metodą inheritFrom()). Jak już wspomniano, ważna jest kolejność, w jakiej następuje dziedziczenie i generalnie lepiej dziedziczyć metody w tej samej kolejności co właściwości (co oznacza, że jeżeli właściwości są dziedziczone przez klasę ClassX, a potem przez ClassY, to metody powinny być dziedzi- czone przez klasy w tej samej kolejności). Następujący kod testuje działanie przykładu z dziedziczeniem wielokrotnym: var oObjZ = new ClassZ(); oObjZ.sayMessageX(); // wyświetla "To jest komunikat X." oObjZ.sayMessageY(); // wyświetla "To jest komunikat Y." oObjZ.sayMessageZ(); // wyświetla "To jest komunikat Z." Powyższy kod wywołuje trzy metody: 1. Metoda sayMessageX(), odziedziczona po klasie ClassX, odwołuje się do właściwości sMessageX, także odziedziczonej po klasie ClassX. 2. Metoda sayMessageY(), odziedziczona po klasie ClassY, odwołuje się do właściwości sMessageY, także odziedziczonej po klasie ClassY. 3. Metoda sayMessageZ(), zdefiniowana w klasie ClassX, odwołuje się do właściwości sMessageZ, także zdefiniowanej w klasie ClassZ. Te trzy metody powinny wyświetlić odpowiednie komunikaty pobrane z odpowiednich właściwości, dowodząc, że dziedziczenie wielokrotne działa. xbObject Strona DevEdge należąca do Netscape a (http://devedge.netscape.com) zawiera wiele przy- datnych informacji i narzędzi wspomagających pisanie skryptów dla programistów sieci WWW. Jedno z takich narzędzi to xbObject (można je pobrać pod adresem http://archive. bclary.com/xbProjects-docs/xbObject/), napisane przez Boba Clary ego z firmy Netscape Communications w 2001 roku, kiedy pojawiła się przeglądarka Netscape 6 (Mozilla 0.6). Narzędzie współpracuje ze wszystkimi wersjami Mozilli, które pojawiły się od tamtego czasu oraz z innymi współcześnie używanymi przeglądarkami (IE, Opera, Safari). Rozdział 4. Dziedziczenie 147 Przeznaczenie [ Pobierz całość w formacie PDF ] |