Совсем недавно я прочитал об использовании вызовов 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");
Спасибо за разъяснение
javascript
inheritance
call
chaining
prototype-programming
Джереми С.
источник
источник
Ответы:
Ответ на настоящий вопрос заключается в том, что вам нужно сделать и то, и другое:
Поэтому не следует вызывать родительский конструктор при настройке наследования. Только при создании экземпляра объекта, наследуемого от другого.
Ответ Криса Моргана почти полный, отсутствует небольшая деталь (свойство конструктора). Позвольте предложить способ настройки наследования.
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
источник
Object.defineProperty(sub.protoype, 'constructor', { enumerable: false, value: sub });
Таким образом вы получите точно такое же «поведение», как когда javascript создает новый экземпляр функции (конструктор установлен как enumerable = false автоматически)Object.create
не была такой хорошей ... обновление. Обратите внимание, что большинствоObject.create
полифиллов реализовано с использованием техники, которую я показал изначально.Идеальный способ сделать это - не делать
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, вы увидите, как они это делают.
источник
Prod_dept.prototype.constructor = Prod_dept;
.Prod_dept.prototype.constructor = Prod_dept;
. Прежде всего, зачем это нужно и почемуProd_dept
вместоProduct
?Prod_dept.prototype
это то, что будет использоваться в качестве прототипа выходных данныхnew Prod_dept()
. (Обычно этот прототип доступен какinstance.__proto__
, хотя это деталь реализации.) Что касается того, почемуconstructor
- это стандартная часть языка и поэтому должна быть предоставлена для единообразия; это правильно по умолчанию, но поскольку мы полностью заменяем прототип, мы должны снова присвоить правильное значение, иначе некоторые вещи будут не в порядке (в этом случае это будет означать, чтоProd_dept
экземпляр будет иметьthis.constructor == Product
, что плохо).Если вы занимались объектно-ориентированным программированием на 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; } }
Теперь мы определили наш класс Person. Что, если бы мы хотели определить другой класс с именем Manager, который наследует некоторые свойства от Person. Нет смысла заново определять все эти свойства, когда мы определяем наш класс Manager, мы можем просто установить его для наследования от класса Person. JavaScript не имеет встроенного наследования, но мы можем использовать следующий метод для реализации наследования:
Inheritance_Manager = {};
// Создаем класс менеджера наследования (название произвольное)Теперь давайте дадим нашему классу наследования метод под названием extend, который принимает аргументы baseClass и subClassas. Внутри метода расширения мы создадим внутренний класс, называемый функцией наследования inheritance () {}. Причина, по которой мы используем этот внутренний класс, состоит в том, чтобы избежать путаницы между прототипами baseClass и subClass. Затем мы заставляем прототип нашего класса наследования указывать на прототип baseClass, как в следующем коде: inheritance.prototype = baseClass. опытный образец; Затем мы копируем прототип наследования в прототип подкласса следующим образом: subClass.prototype = new inheritance (); Следующее, что нужно сделать, - это указать конструктор для нашего подкласса следующим образом: subClass.prototype.constructor = subClass; Закончив прототипирование нашего подкласса, мы можем указать следующие две строки кода, чтобы установить некоторые указатели базового класса.
Вот полный код нашей функции расширения:
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.'); }
мы наследуем от человека
Если вы заметили, мы только что вызвали метод расширения нашего класса Inheritance_Manager и в нашем случае передали диспетчер подклассов, а затем - человека базового класса. Обратите внимание, что порядок здесь очень важен. Если вы поменяете их местами, наследование не будет работать так, как вы планировали, если вообще. Также обратите внимание, что вам нужно будет указать это наследование, прежде чем вы действительно сможете определить наш подкласс. Теперь давайте определим наш подкласс:
Мы можем добавить больше методов, как показано ниже. Наш класс 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
источник