2008-12-31 13 views
7

Widzę dużo kodu tak:Konwencja prototypowego dziedziczenia w JavaScripcie

function Base() {} 
function Sub() {} 
Sub.prototype = new Base(); 

Jeśli jednak zrobić:

s = new Sub(); 
print(s.constructor == Sub); 

To jest fałszywe. Wydaje mi się to mylące, ponieważ konstruktor s jest, w rzeczy samej, Sub. Czy to jest konwencjonalne/lepiej to robić?

function Base() {} 
function Sub() {} 
Sub.prototype = new Base(); 
Sub.prototype.constructor = Sub; 

czy to naprawdę nie ma znaczenia?

+0

Właśnie przeprowadziłem porównanie przez stronę html jako alert (s.constructor == Sub) i to zwróciło prawdę –

+0

Wiele frameworks dostosowuje właściwość 'constructor' poprawnie wskaż konstruktor podklasy. Mam post, który zajmuje się tym i innymi problemami w kodzie, który pokazałeś powyżej http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html –

Odpowiedz

9

„konstruktor” nie robić to, co wygląda na to, że tak. To, oprócz nietypowości, jest dobrym powodem, aby go nie używać - trzymać się instancji i prototypu.

Technicznie: "konstruktor" nie jest właściwością instancji "s", jest własnością obiektu prototypowego "Sub". Kiedy utworzysz funkcję "Sub" w Mozilli, otrzymasz nowy, domyślny obiekt Sub.prototype, który ma "konstruktor", wskazując drogę do funkcji Sub jako grzeczność.

Jednak należy zastąpić ten prototyp nowym Base(). Oryginalny domyślny prototyp z łączem z powrotem do Sub zostaje utracony; zamiast tego Sub.prototype jest instancją Base bez żadnej nadpisującej właściwości 'constructor'. A więc:

new Sub().constructor=== 
Sub.prototype.constructor=== 
new Base().constructor=== 
Base.prototype.constructor=== 
Base 

... aż do najbardziej podstawowego obiektu, którego prototyp nie został zmieniony.

Czy to jest konwencjonalne/lepiej to zrobić?

W przypadku obiektów/klas JavaScript nie ma jednej konwencji; system metaklasy każdej biblioteki zachowuje się nieco inaczej. Nie widziałem takiego, który ręcznie zapisuje "konstruktor" do każdej klasy pochodnej, ale wydaje się równie dobrym rozwiązaniem, jeśli naprawdę chcesz mieć dostęp do prawdziwego konstruktora; spowoduje to również, że kod będzie zgodny z przeglądarkami/silnikami, które nie dają "konstruktora".

Zastanowiłbym się nad nadaniem mu innej nazwy, aby uniknąć nieporozumień z istniejącą i odmiennie zachowującą się właściwością "konstruktora".

3

Jeśli chcesz sprawdzić, czy obiekt jest dokładnie instancją Sub użyć operatora instanceof: -

print(s instanceof Sub); 

Jeśli chcesz wiedzieć, czy obiekt jest instancją Sub lub instancją sub -class z Sub użyć metody isPrototypeOf: -

print(Sub.prototype.isPrototypeOf(s)); 
+0

dzięki za radę, to ma sens – Claudiu

+0

Kolejny dobry Anthony;) – Rob

1

Tak,

Sub.prototype.constructor = Sub; 

pozwala ci używać instanceof ale jest lepszym rozwiązaniem. Spójrz tutaj:, TDD JS Inheritance on GitHub i znajdź wzór pasożytniczej kombinacji dziedzicznej z dziedziczoną kombinacją. Kod to TDD, więc powinieneś być w stanie bardzo szybko go zgarnąć, a następnie po prostu zmienić nazwy, aby zacząć. Zasadniczo to jest to, czego używa YAHOO.lang.extend (źródło: pracownik yahoo i autor Nicholas Zakas Professional JavaScript dla programistów internetowych, 2. ED, strona 181). Dobra książka przy okazji (nie w żaden sposób powiązana!)

Dlaczego? Ponieważ klasyczny wzorzec, z którym pracujesz, ma odniesienia do zmiennych statycznych (jeśli utworzysz var arr = [1,2] w obiekcie bazowym, WSZYSTKIE instancje będą miały uprawnienia do odczytu/zapisu i "współużytkują stan" z "arr"! używaj kradzieży konstruktorów możesz obejść to, zobacz moje przykłady