Całkiem niedawno czytałem o używaniu wywołań JavaScript w MDC
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/call
jeden link z przykładu pokazanego poniżej, nadal nie rozumiem.
Dlaczego używają tutaj dziedziczenia w ten sposób
Prod_dept.prototype = new Product();
czy to konieczne? Ponieważ istnieje wywołanie superkonstruktora w programie
Prod_dept()
w każdym razie w ten sposób
Product.call
czy to po prostu nietypowe zachowanie? Kiedy lepiej jest użyć wywołania dla superkonstruktora lub łańcucha prototypów?
function Product(name, value){
this.name = name;
if(value >= 1000)
this.value = 999;
else
this.value = value;
}
function Prod_dept(name, value, dept){
this.dept = dept;
Product.call(this, name, value);
}
Prod_dept.prototype = new Product();
// since 5 is less than 1000, value is set
cheese = new Prod_dept("feta", 5, "food");
// since 5000 is above 1000, value will be 999
car = new Prod_dept("honda", 5000, "auto");
Dzięki za wyjaśnienie sprawy
javascript
inheritance
call
chaining
prototype-programming
Jeremy S.
źródło
źródło
Odpowiedzi:
Odpowiedź na prawdziwe pytanie jest taka, że musisz zrobić jedno i drugie:
Dlatego podczas konfigurowania dziedziczenia nie należy wywoływać konstruktora elementu nadrzędnego. Tylko podczas tworzenia wystąpienia obiektu, który dziedziczy po innym.
Odpowiedź Chrisa Morgana jest prawie kompletna, brakuje jej małego szczegółu (właściwość konstruktora). Zasugeruję metodę konfigurowania dziedziczenia.
function extend(base, sub) { // Avoid instantiating the base class just to setup inheritance // Also, do a recursive merge of two prototypes, so we don't overwrite // the existing prototype, but still maintain the inheritance chain // Thanks to @ccnokes var origProto = sub.prototype; sub.prototype = Object.create(base.prototype); for (var key in origProto) { sub.prototype[key] = origProto[key]; } // The constructor property was set wrong, let's fix it Object.defineProperty(sub.prototype, 'constructor', { enumerable: false, value: sub }); } // Let's try this function Animal(name) { this.name = name; } Animal.prototype = { sayMyName: function() { console.log(this.getWordsToSay() + " " + this.name); }, getWordsToSay: function() { // Abstract } } function Dog(name) { // Call the parent's constructor Animal.call(this, name); } Dog.prototype = { getWordsToSay: function(){ return "Ruff Ruff"; } } // Setup the prototype chain the right way extend(Animal, Dog); // Here is where the Dog (and Animal) constructors are called var dog = new Dog("Lassie"); dog.sayMyName(); // Outputs Ruff Ruff Lassie console.log(dog instanceof Animal); // true console.log(dog.constructor); // Dog
Zobacz mój wpis na blogu, aby uzyskać jeszcze więcej cukru składniowego podczas tworzenia zajęć. http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html
Technika skopiowana z Ext-JS i http://www.uselesspickles.com/class_library/ oraz komentarz z https://stackoverflow.com/users/1397311/ccnokes
źródło
Object.defineProperty(sub.protoype, 'constructor', { enumerable: false, value: sub });
ten sposób W ten sposób uzyskasz dokładnie to samo "zachowanie" jak gdy javascript tworzy nowe wystąpienie funkcji (konstruktor jest ustawiony jako wyliczalny = false automatycznie)Object.create
nie było tak dobrze wspierane ... aktualizacja. Zauważ, że większośćObject.create
polyfillów jest realizowana przy użyciu techniki, którą pokazałem pierwotnie.Idealnym sposobem na to jest nie robienie tego
Prod_dept.prototype = new Product();
, ponieważ wywołuje toProduct
konstruktora. Więc idealnym sposobem jest sklonowanie go z wyjątkiem konstruktora, coś takiego:function Product(...) { ... } var tmp = function(){}; tmp.prototype = Product.prototype; function Prod_dept(...) { Product.call(this, ...); } Prod_dept.prototype = new tmp(); Prod_dept.prototype.constructor = Prod_dept;
Następnie w czasie budowy wywoływany jest superkonstruktor, co jest tym, czego chcesz, ponieważ wtedy również możesz przekazać parametry.
Jeśli spojrzysz na takie rzeczy, jak Google Closure Library, zobaczysz, jak to robią.
źródło
Prod_dept.prototype.constructor = Prod_dept;
.Prod_dept.prototype.constructor = Prod_dept;
. Po pierwsze, dlaczego jest potrzebny i dlaczegoProd_dept
zamiast tego wskazujeProduct
?Prod_dept.prototype
jest tym, co zostanie użyte jako prototyp wynikunew Prod_dept()
. (Zwykle ten prototyp jest dostępny takinstance.__proto__
, jakby był to szczegół implementacji). A jeśli chodzi o powódconstructor
- jest to standardowa część języka i dlatego powinna być zapewniona dla spójności; Domyślnie jest to poprawne, ale ponieważ całkowicie zastępujemy prototyp, musimy ponownie przypisać odpowiednią wartość, w przeciwnym razie niektóre rzeczy nie będą rozsądne (w tym przypadku oznaczałoby to, że wystąpiłabyProd_dept
instancjathis.constructor == Product
, co jest złe).Jeśli zrobiłeś już programowanie obiektowe w JavaScript, wiesz, że możesz utworzyć klasę w następujący sposób:
Person = function(id, name, age){ this.id = id; this.name = name; this.age = age; alert('A new person has been accepted'); }
Jak dotąd osoba z klasy ma tylko dwie właściwości i zamierzamy podać jej kilka metod. Prostym sposobem na to jest użycie obiektu „prototypu”. Począwszy od JavaScript 1.1, obiekt prototypowy został wprowadzony w JavaScript. Jest to obiekt wbudowany, który upraszcza proces dodawania niestandardowych właściwości i metod do wszystkich wystąpień obiektu. Dodajmy 2 metody do naszej klasy, używając jej obiektu „prototyp” w następujący sposób:
Person.prototype = { /** wake person up */ wake_up: function() { alert('I am awake'); }, /** retrieve person's age */ get_age: function() { return this.age; } }
Teraz zdefiniowaliśmy naszą klasę Person. A co by było, gdybyśmy chcieli zdefiniować inną klasę o nazwie Manager, która dziedziczy niektóre właściwości z Person. Nie ma sensu ponownie definiować wszystkich tych właściwości, kiedy definiujemy naszą klasę Manager, możemy po prostu ustawić ją tak, aby dziedziczyła z klasy Person. JavaScript nie ma wbudowanego dziedziczenia, ale możemy użyć następującej techniki do zaimplementowania dziedziczenia:
Inheritance_Manager = {};
// Tworzymy klasę menedżera dziedziczenia (nazwa jest dowolna)Teraz dajmy naszej klasie dziedziczenia metodę o nazwie extension, która przyjmuje argumenty baseClass i subClassas. W ramach metody rozszerzania utworzymy klasę wewnętrzną o nazwie inheritance function inheritance () {}. Powodem, dla którego używamy tej klasy wewnętrznej, jest uniknięcie pomyłki między prototypami baseClass i subClass. Następnie sprawiamy, że prototyp naszej klasy dziedziczenia wskazuje na prototyp baseClass, tak jak w następującym kodzie: inheritance.prototype = baseClass. prototyp; Następnie kopiujemy prototyp dziedziczenia do prototypu podklasy w następujący sposób: subClass.prototype = new inheritance (); Następną rzeczą jest określenie konstruktora dla naszej podklasy w następujący sposób: subClass.prototype.constructor = subClass; Po zakończeniu naszego prototypowania podklasy możemy określić następne dwa wiersze kodu, aby ustawić wskaźniki klasy bazowej.
Oto pełny kod naszej funkcji rozszerzającej:
Inheritance_Manager.extend = function(subClass, baseClass) { function inheritance() { } inheritance.prototype = baseClass.prototype; subClass.prototype = new inheritance(); subClass.prototype.constructor = subClass; subClass.baseConstructor = baseClass; subClass.superClass = baseClass.prototype; }
Teraz, gdy zaimplementowaliśmy nasze dziedziczenie, możemy zacząć używać go do rozszerzania naszych klas. W tym przypadku zamierzamy rozszerzyć naszą klasę Person na klasę Manager w następujący sposób:
Definiujemy klasę Manager
Manager = function(id, name, age, salary) { Person.baseConstructor.call(this, id, name, age); this.salary = salary; alert('A manager has been registered.'); }
sprawiamy, że dziedziczymy po osobie
Jeśli zauważyłeś, właśnie wywołaliśmy metodę rozszerzoną naszej klasy Inheritance_Manager i przekazaliśmy Menedżera podklasy w naszym przypadku, a następnie osobę baseClass. Zwróć uwagę, że kolejność jest tutaj bardzo ważna. Jeśli je zamienisz, dziedziczenie nie będzie działać tak, jak zamierzałeś, jeśli w ogóle. Zauważ również, że będziesz musiał określić to dziedziczenie, zanim będziesz mógł faktycznie zdefiniować naszą podklasę. Teraz zdefiniujmy naszą podklasę:
Możemy dodać więcej metod, jak ta poniżej. Nasza klasa Manager zawsze będzie miała metody i właściwości zdefiniowane w klasie Person, ponieważ dziedziczy po niej.
Manager.prototype.lead = function(){ alert('I am a good leader'); }
Aby to przetestować, stwórzmy dwa obiekty, jeden z klasy Person i jeden z odziedziczonej klasy Manager:
var p = new Person(1, 'Joe Tester', 26); var pm = new Manager(1, 'Joe Tester', 26, '20.000');
Zapraszam do uzyskania pełnego kodu i dodatkowych komentarzy pod adresem : http://www.cyberminds.co.uk/blog/articles/how-to-implement-javascript-inheritance.aspx
źródło