Вопрос:

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

javascript inheritance call chaining prototype-programming

82795 просмотра

3 ответа

3530 Репутация автора

Совсем недавно я читал об использовании вызовов 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");

Спасибо за разъяснение

Автор: Jeremy S. Источник Размещён: 11.11.2010 09:28

Ответы (3)


30 плюса

61884 Репутация автора

Идеальный способ сделать это - не делать 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, вы увидите, как они это делают.

Автор: Chris Morgan Размещён: 11.11.2010 09:32

107 плюса

71920 Репутация автора

Решение

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

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

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

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

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

См. Мой пост в блоге для еще большего синтаксического сахара при создании классов. 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

Автор: Juan Mendes Размещён: 08.12.2010 03:52

6 плюса

169 Репутация автора

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

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

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

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

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

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

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

Теперь давайте передадим нашему классу наследования метод под названием extend, который принимает аргументы baseClass и subClassas. В рамках метода extends мы создадим внутренний класс под названием унаследованная функция 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

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

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

Мы можем добавить больше методов, как показано ниже. Наш класс 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

Автор: Joe Francis Размещён: 21.12.2011 09:20
Вопросы из категории :
32x32