Наследование JavaScript: вызов супер-конструктора или использование прототипа?

Совсем недавно я прочитал об использовании JavaScript-вызовов в MDC

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

одна ссылка из приведенного ниже примера, я все еще не понимаю.

Почему они здесь используют наследование

Prod_dept.prototype = new Product();

Это необходимо? Потому что есть вызов супер-конструктора в

Prod_dept()

в любом случае, как этот

Product.call

это просто из-за обычного поведения? Когда лучше использовать вызов супер-конструктора или использовать цепочку прототипов?

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");

Спасибо, что поняли, что делать.

Ответ 1

Ответ на реальный вопрос заключается в том, что вам нужно сделать оба:

  • Установка прототипа в экземпляр родителя инициализирует цепочку прототипов (наследование), это выполняется только один раз (поскольку объект прототипа является общим).
  • Вызов родительского конструктора инициализирует сам объект, это делается с каждым экземпляром (вы можете передавать разные параметры при каждом его создании).

Следовательно, вы не должны вызывать родительский конструктор при настройке наследования. Только при создании экземпляра объекта, который наследуется от другого.

Ответ Криса Моргана почти завершен, отсутствует небольшая деталь (свойство конструктора). Позвольте мне предложить метод настройки наследования.

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 fix it
  Object.defineProperty(sub.prototype, 'constructor', { 
    enumerable: false, 
    value: sub 
  });
}

// Let 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 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

См. мое сообщение в блоге для еще большего синтаксического сахара при создании классов. http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html

Техника скопирована из Ext-JS и http://www.uselesspickles.com/class_library/ и комментарий https://stackoverflow.com/users/1397311/ccnokes

Ответ 2

Идеальный способ сделать это - не делать Prod_dept.prototype = new Product();, потому что это вызывает конструктор Product. Поэтому идеальный способ - клонировать его, кроме конструктора, примерно так:

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;

Затем супер конструктор вызывается во время построения, что вам нужно, потому что тогда вы также можете передавать параметры.

Если вы посмотрите на такие вещи, как Google Closure Library, вы увидите, как они это делают.

Ответ 3

Если вы сделали объектно-ориентированное программирование в JavaScript, вы узнаете, что вы можете создать класс следующим образом:

Person = function(id, name, age){
    this.id = id;
    this.name = name;
    this.age = age;
    alert('A new person has been accepted');
}

До сих пор у нашего класса только два свойства, и мы собираемся дать ему некоторые методы. Чистый способ сделать это для использования его объекта 'prototype'. Начиная с JavaScript 1.1, объект-прототип был введен в JavaScript. Это встроенный объект, который упрощает процесс добавления пользовательских свойств и методов ко всем экземплярам объекта. Давайте добавим 2 метода к нашему классу, используя его объект 'prototype' следующим образом:

Person.prototype = {
    /** wake person up */
    wake_up: function() {
        alert('I am awake');
    },

    /** retrieve person age */
    get_age: function() {
        return this.age;
    }
}

Теперь мы определили наш класс Person. Что делать, если мы хотим определить другой класс под названием "Менеджер", который наследует некоторые свойства от Person. Нет смысла переопределять все эти свойства снова, когда мы определяем наш класс Manager, мы можем просто установить его наследование из класса Person. JavaScript не имеет встроенного наследования, но мы можем использовать метод для реализации наследования следующим образом:

Inheritance_Manager = {};//Создаем класс менеджера наследования (имя произвольно)

Теперь дадим нашему классу наследования метод, называемый extend, который принимает аргументы baseClass и subClassas. В рамках метода extend мы создадим внутренний класс, называемый функцией наследования inheritance() {}. Причина, по которой мы используем эту внутреннюю класс должен избегать путаницы между прототипами baseClass и subClass. Затем мы создаем прототип нашего класса наследования для прототипа baseClass, как со следующим кодом: inheritance.prototype = baseClass. опытный образец; Затем мы копируем прототип наследования в прототип subClass следующим образом: subClass.prototype = new inheritance(); Следующее - указать конструктор для нашего субкласса следующим образом: subClass.prototype.constructor = subClass; После завершения прототипирования нашего субкласса мы можем указать следующие две строки кода, чтобы установить некоторые указатели базового класса.

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

Вот полный код нашей расширенной функции:

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;
}

Теперь, когда мы реализовали наше наследование, мы можем начать использовать его для расширения наших классов. В этом случае мы собираемся расширьте класс Person классом Manager следующим образом:

Определим класс Менеджера

Manager = function(id, name, age, salary) {
    Person.baseConstructor.call(this, id, name, age);
    this.salary = salary;
    alert('A manager has been registered.');
}

мы наследуем форму Person

Inheritance_Manager.extend(Manager, Person);

Если вы заметили, мы только что назвали метод расширения нашего класса Inheritance_Manager и передали в этом случае диспетчер subClass, а затем - имя baseClass. Обратите внимание, что порядок здесь очень важен. Если вы меняете их, наследование не будет работать так, как вы планировали, если вообще. Также обратите внимание, что вам нужно будет указать это наследование, прежде чем вы сможете определить наш субкласс. Теперь определим наш подкласс:

Мы можем добавить несколько методов, как показано ниже. Наш класс Manager всегда будет иметь методы и свойства, определенные в классе Person, потому что он наследует его.

Manager.prototype.lead = function(){
   alert('I am a good leader');
}

Теперь, чтобы протестировать его, создадим два объекта: один из класса Person и один из унаследованного класса Manager:

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

Не стесняйтесь получать полный код и больше комментариев по адресу: http://www.cyberminds.co.uk/blog/articles/how-to-implement-javascript-inheritance.aspx