Dziedziczenie Javascript: wywołać super-konstruktor czy użyć prototype chain?

Całkiem niedawno czytałem o użyciu połączeń JavaScript w MDC

Https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/call

Jeden linke z poniższego przykładu, nadal nie rozumiem.

Dlaczego używają dziedziczenia w ten sposób

Prod_dept.prototype = new Product();
Czy to konieczne? Ponieważ istnieje wezwanie do super-konstruktora w
Prod_dept()

W każdym razie, jak to

Product.call
Czy to tylko zwykłe zachowanie? Kiedy to jest lepiej użyć call for the super-constructor or use the prototype chain?
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");

Thanks for making things clearer

Author: Tom van der Woerdt, 2010-11-11

3 answers

ODPOWIEDŹ na prawdziwe pytanie jest taka, że musisz zrobić jedno i drugie:

  • ustawienie prototypu na instancję rodzica inicjalizuje łańcuch prototypów( dziedziczenie), odbywa się to tylko raz (ponieważ obiekt prototype jest współdzielony).
  • wywołanie konstruktora rodzica inicjalizuje sam obiekt, odbywa się to przy każdej instancji (za każdym razem można przekazać inne parametry).

Dlatego nie należy wywoływać konstruktora rodzica, gdy zakładanie spadku. Tylko wtedy, gdy tworzymy instancję obiektu, który dziedziczy po innym.

ODPOWIEDŹ Chrisa Morgana jest prawie kompletna, brakuje drobnego szczegółu (własności konstruktora). Pozwól, że zaproponuję metodę ustawienia 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 dowiedzieć się więcej o cukrze składniowym podczas tworzenia klas. http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html

Technika skopiowana z Ext-JS i http://www.uselesspickles.com/class_library / i komentarz z https://stackoverflow.com/users/1397311/ccnokes

 104
Author: Juan Mendes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:11

Idealnym sposobem na to jest nie robić Prod_dept.prototype = new Product();, ponieważ to wywołuje konstruktor Product. Tak więc idealnym sposobem jest sklonowanie go z wyjątkiem konstruktora, coś w tym stylu:

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;

Wtedy super konstruktor jest wywoływany w czasie budowy, co jest tym, czego chcesz, ponieważ wtedy możesz również przekazać parametry.

Jeśli spojrzysz na rzeczy takie jak Biblioteka zamknięcia Google zobaczysz, że tak to robią.

 28
Author: Chris Morgan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-12-08 22:57:56

Jeśli wykonałeś Programowanie obiektowe w JavaScript, będziesz wiedział, ż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 na razie nasza klasa ma tylko dwie właściwości i podamy jej kilka metod. Czystym sposobem na to jest aby użyć swojego "prototypowego" obiektu. Począwszy od JavaScript 1.1, prototypowy obiekt został wprowadzony w JavaScript. Jest to wbudowany obiekt, który upraszcza proces dodawania niestandardowych właściwości i metod do wszystkich wystąpień obiekt. Dodajmy 2 metody do naszej klasy używając obiektu' prototype ' 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ą klasową osobę. Co by było, gdybyśmy chcieli zdefiniować inną klasę o nazwie Manager, która dziedziczy pewne właściwości od Person. Nie ma sensu ponownie definiować wszystkich tych właściwości kiedy zdefiniujemy naszą klasę Manager, możemy po prostu ustawić ją na dziedziczenie od class Person. JavaScript nie ma wbudowanego dziedziczenia, ale możemy użyć techniki do zaimplementowania dziedziczenia jako następuje:

Inheritance_Manager = {};//tworzymy klasę menedżera dziedziczenia (nazwa jest dowolna)

Dajmy teraz naszej klasie dziedziczenia metodę o nazwie extend, która pobiera argumenty baseClass i subClassas. W ramach metody extend utworzymy wewnętrzną klasę o nazwie funkcja dziedziczenia inheritance () {}. Powód, dla którego używamy tego wewnętrznego klasa ma na celu uniknięcie pomylenia prototypów klasy baseClass i podklasy. Następnie wykonujemy prototyp naszej klasy dziedziczenia wskazuje na prototyp baseClass jak z poniższym kodem: spadek.prototype = baseClass. prototype; Następnie kopiujemy prototyp dziedziczenia do prototypu podklasy w następujący sposób: subClass.prototype = nowe dziedziczenie(); Następną rzeczą jest określenie konstruktora dla naszej podklasy w następujący sposób: subClass.prototyp.constructor = subClass; Po zakończeniu prototypowania podklasy, możemy określić następne dwie linie kodu, aby ustawić kilka wskaźników klas bazowych.

subClass.baseConstructor = baseClass;
subClass.superClass = baseClass.prototype;

Oto Pełny kod do naszego funkcja rozszerzenia:

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 wdrożyliśmy nasze dziedzictwo, możemy zacząć używać go do rozszerzania naszych klas. W tym przypadku zamierzamy rozszerz naszą klasę osoby na klasę menedżera w następujący sposób:

Definiujemy klasę Menedżera

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 postać osoby

Inheritance_Manager.extend(Manager, Person);

Jeśli zauważyłeś, właśnie wywołaliśmy metodę extend naszej klasy Inheritance_Manager i przekazaliśmy Menedżera podklas w naszym przypadku, a następnie osobę baseClass. Zauważ, że porządek jest tutaj bardzo ważny. Jeśli je zamienisz, spadek 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ł 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');
}

Teraz aby to przetestować stwórzmy dwa obiekty, jeden z klasy Person i jeden od dziedzicznego kierownika klasy:

var p = new Person(1, 'Joe Tester', 26);
var pm = new Manager(1, 'Joe Tester', 26, '20.000');

Zapraszam do zapoznania się z pełnym kodem i więcej komentarzy na: http://www.cyberminds.co.uk/blog/articles/how-to-implement-javascript-inheritance.aspx

 6
Author: Joe Francis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-21 21:20:32