Наследование 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");
Спасибо, что прояснили ситуацию
3 ответа:
ответ на реальный вопрос заключается в том, что вам нужно сделать так:
- установка прототипа на экземпляр родительского инициализирует цепочку прототипов (наследование), это делается только один раз (так как объект прототипа является общим).
- вызов родительского конструктора инициализирует сам объект, это делается с каждым экземпляром (вы можете передавать разные параметры каждый раз, когда вы его создаете).
таким образом, вы не должны называть конструктор родителя при настройке наследования. Только при создании экземпляра объекта, который наследуется от другого.
ответ Криса Моргана почти завершен, отсутствует небольшая деталь (свойство конструктора). Позвольте мне предложить способ настройки наследования.
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
идеальный способ сделать это -не do
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, вы увидите, как они это делают.
если вы сделали объектно-ориентированное программирование на JavaScript, вы будете знать, что вы можете создать класс следующим образом:
Person = function(id, name, age){ this.id = id; this.name = name; this.age = age; alert('A new person has been accepted'); }
до сих пор наш класс person имеет только два свойства, и мы собираемся дать ему некоторые методы. Чистый способ сделать это чтобы использовать его "прототип" объекта. Начиная с 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; } }
теперь мы определили наш класс человек. Что делать, если мы хотим определить другой класс под названием Manager, который наследует некоторые свойства от Person. Нет смысла переопределять все эти свойства снова, когда мы определяем наш класс менеджера, мы можем просто установить его наследование от класса Person. JavaScript не имеет встроенного наследования, но мы можем использовать технику для реализации наследования как следует:
Inheritance_Manager = {};
//мы создаем класс менеджера наследования (имя произвольное)теперь давайте дадим нашему классу наследования метод под названием extend, который принимает аргументы базового класса и подкласса. В рамках метода extend мы создадим внутренний класс с именем inheritance function inheritance () { }. Причина, по которой мы используем этот внутренний класс должен избегать путаницы между прототипами базового класса и подкласса. Далее мы делаем прототип нашего класса наследования укажите на прототип базового класса, как показано в следующем коде: наследование.прототип = базовый класс. прототип; Затем мы копируем прототип наследования в прототип подкласса следующим образом: подкласс.прототип = новое наследование(); Далее необходимо указать конструктор для нашего подкласса следующим образом: подкласс.прототип.конструктор = подкласс; После завершения нашего прототипирования подкласса мы можем указать следующие две строки кода, чтобы установить некоторые указатели базового класса.
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.'); }
мы заставляем его наследовать форму человека
Inheritance_Manager.extend(Manager, Person);
если вы заметили, мы только что вызвали метод extend нашего класса Inheritance_Manager и передали менеджер подклассов наш случай, а затем человек из базового класса. Обратите внимание, что порядок здесь очень важен. Если вы поменяете их местами, то наследство не будет работать как задумано, если вообще. Также обратите внимание, что вам нужно будет указать это наследование, прежде чем вы сможете фактически определить наш подкласс. Теперь определим наш подкласс:
мы можем добавить больше методов, как показано ниже. Наш класс Manager всегда будет иметь методы и свойства, определенные в классе Person, потому что он наследует от оно.
Manager.prototype.lead = function(){ alert('I am a good leader'); }
теперь, чтобы проверить это, давайте создадим два объекта, один из класса Person и один из унаследованного менеджера классов:
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