Modyfikacja obiektów w ECMAScript
- Poprzednia strona Definiowanie klas lub obiektów
- Następna strona Przykład mechanizmu dziedziczenia
Poprzez użycie ECMAScript, można nie tylko tworzyć obiekty, ale także modyfikować zachowanie istniejących obiektów.
Atrybut 'prototype' może nie tylko zdefiniować atrybuty i metody konstruktora, ale także dodać atrybuty i metody do lokalnego obiektu.
Tworzenie nowych metod
Tworzenie nowych metod za pomocą istniejących metod
Można użyć atrybutu prototype do zdefiniowania nowych metod dla istniejących klas, jak dla własnych klas. Na przykład, pamiętasz metodę toString() klasy Number? Jeśli podasz jej parametr 16, wyświetli szesnastkowy ciąg znaków. Jeśli parametr metody to 2, wyświetli ciąg binarny. Możemy utworzyć metodę, która bezpośrednio konwertuje obiekt liczby na ciąg znaków szesnastkowego systemu. Tworzenie tej metody jest bardzo proste:
Number.prototype.toHexString = function() { return this.toString(16); };
W tym środowisku, kluczowe słowo this wskazuje na instancję Number, więc można w pełni uzyskać dostęp do wszystkich metod Number. Z tym kodem można wykonać następujące operacje:
var iNum = 15; alert(iNum.toHexString()); //Wyświetla "F"
Ponieważ liczba 15 jest równa F w szesnastkowym systemie, ostrzeżenie będzie wyświetlało "F".
Zmiana nazw istniejących metod
Możemy również zmienić nazwy istniejących metod na bardziej zrozumiałe. Na przykład, można dodać do klasy Array dwie metody enqueue() i dequeue(), które powtarzają istniejące metody push() i shift():
Array.prototype.enqueue = function(vItem) { this.push(vItem); }; Array.prototype.dequeue = function() { return this.shift(); };
Dodaj metody niezależne od istniejących metod
Oczywiście, można dodać metody niezależne od istniejących metod. Na przykład, zakładając, że chcemy sprawdzić pozycję elementu w tablicy, nie ma lokalnej metody do tego celu. Możemy łatwo utworzyć poniższą metodę:
Array.prototype.indexOf = function (vItem) { for (var i=0; i<this.length; i++) { if (vItem == this[i]) { return i; } } return -1; }
Metoda indexOf() jest zgodna z odpowiednią metodą w klasie String, wyszukuje każdy element w tablicy, aż znajdzie element, który jest identyczny z przekazanym elementem. Jeśli znajdzie taki element, zwraca jego pozycję, w przeciwnym razie zwraca -1. Z taką definicją możemy napisać poniższy kod:
var aColors = new Array("red","green","blue"); alert(aColors.indexOf("green")); //wyświetla "1"
Dodawanie nowych metod do lokalnych obiektów
Ostatnio, aby dodać nową metodę do każdego lokalnego obiektu w ECMAScript, musi ona być zdefiniowana na atrybucie prototype obiektu Object. Jak już wspomniano w poprzednich rozdziałach, wszystkie lokalne obiekty dziedziczą obiekt Object, więc każda zmiana w obiekcie Object wpływa na wszystkie lokalne obiekty. Na przykład, jeśli chcesz dodać metodę wyświetlającą bieżącą wartość obiektu za pomocą komunikatu ostrzegawczego, możesz użyć poniższego kodu:
Object.prototype.showValue = function () { alert(this.valueOf()); }; var str = "hello"; var iNum = 25; str.showValue(); //wyświetla "hello" iNum.showValue(); //wyświetla "25"
Tutaj, obiekty String i Number dziedziczą metodę showValue() od obiektu Object, a gdy wywołuje się tę metodę na ich obiektach, wyświetla "hello" i "25".
Przedefiniowanie istniejących metod
Tak jak można dodać nowe metody do istniejących klas, można również przedefiniować istniejące metody. Jak omówiono w poprzednich rozdziałach, nazwa funkcji jest wskaźnikiem do funkcji, więc można ją łatwo skierować do innej funkcji. Co się stanie, jeśli zmodyfikujesz lokalną metodę, taką jak toString()?
Function.prototype.toString = function() { return "Kod funkcji ukryty"; }
Poprzedni kod jest całkowicie legalny i wynik jego działania jest zgodny z oczekiwaniami:
function sayHi() { alert("hi"); } alert(sayHi.toString()); //wyświetla "Kod funkcji ukryty"
Może jeszcze pamiętacie, że w rozdziale o obiekcie Function omówiliśmy metodę toString() tej funkcji, która zazwyczaj wyświetla kod źródłowy funkcji. Można nadpisać tę metodę, aby zwrócić inny ciąg znaków (w tym przykładzie, można zwrócić "Kod funkcji ukryty"). Co się dzieje z oryginalną funkcją, do której wskazuje toString()? Zostanie ona zwrócona do programu recyklingu nieużywanych jednostek pamięci, ponieważ została całkowicie porzucona. Nie ma metody przywracającej oryginalną funkcję, więc bezpiecznym podejściem przed nadpisaniem oryginalnej metody jest przechowanie jej wskaźnika, aby można było go użyć w przyszłości. Czasami możesz nawet wywołać oryginalną metodę w nowej metodzie:
Function.prototype.originalToString = Function.prototype.toString; Function.prototype.toString = function() { if (this.originalToString().length > 100) { return "Funkcja zbyt długa do wyświetlenia."; } else { return this.originalToString(); } };
W tym kodzie, pierwsza linia zapisuje odniesienie do bieżącej metody toString() w atrybucie originalToString. Następnie zastępuje się metodę toString() niestandardową metodą, która sprawdza, czy długość kodu funkcji jest większa niż 100. Jeśli tak, zwraca komunikat błędu, że kod funkcji jest zbyt długi, w przeciwnym razie wywołuje metodę originalToString() i zwraca kod funkcji.
Bardzo późne wiązanie (Very Late Binding)
Technicznie rzecz biorąc, nie istnieje bardzo późne wiązanie. Ta książka używa tego terminu do opisania zjawiska w ECMAScript, które umożliwia definiowanie metod obiektu po jego instancjalizacji. Na przykład:
var o = new Object(); Object.prototype.sayHi = function () { alert("hi"); }; o.sayHi();
W większości języków programowania, metody obiektu muszą być zdefiniowane przed instancjalizacją obiektu. Tutaj, metoda sayHi() jest dodawana po utworzeniu instancji klasy Object. W tradycyjnych językach nie słyszałem o takiej operacji, ani o metodzie, która automatycznie przypisuje instancji obiektu Object i natychmiast ją używa (w następnym wierszu).
Uwaga:Niedozwolone jest używanie metod bardzo późnego wiązania, ponieważ trudno je śledzić i rejestrować. Jednakże, warto poznać tę możliwość.
- Poprzednia strona Definiowanie klas lub obiektów
- Następna strona Przykład mechanizmu dziedziczenia