Вопрос

Я знаю, что есть много похожих вопросов, на которые есть масса отличных ответов.Я попытался взглянуть на классические методы наследования, или эти методы закрытия и т.д.Почему-то я считаю, что для меня это более или менее "хакерские" методы, поскольку на самом деле это не то, для чего предназначен javascript.(Добро пожаловать, если кто-нибудь поправит меня, если я ошибаюсь).Хорошо, пока это работает, я удовлетворяюсь классическим шаблоном наследования, таким как:

PARENTClass = function (basevar) { do something here; };
PARENTClass.prototype = { a: b, c: d}; // prototype is auto gen 

// Inheritance goes here
CHILDClass = function (childvar) { do something; };
CHILDClass.prototype = new PARENTClass(*1); // Actual inheritance to the prototype statement
// Instance
CHILDInstance = new CHILDClass(whatever);

Выше каким-то образом, насколько я понимаю, описано наследование JS.Но один сценарий, который я понятия не имею, как реализовать, заключается в том, что если я захочу выполнить некоторую инициализацию ВО время создания объекта (т. Е. внутри конструктора), и новый объект можно будет использовать сразу....Моя иллюстрация к проблеме может быть не слишком ясной, поэтому позвольте мне использовать следующий псевдоним C #, чтобы объяснить, что я хочу сделать:

class PARENT {
    public PARENT (basevar) { ... }
}
class CHILD : PARENT {
    public CHILD (basevar) : PARENT (basevar) // constructor of child, and call parent constructor during construct.
    { ... }
}

По какой-то причине (например, init.Элементы пользовательского интерфейса), помещение их в конструктор кажется лучшим способом сделать это.У кого-нибудь есть идеи о том, как я могу это сделать.

PS:в * 1 я понятия не имею, что я должен туда поместить.PS2:В описанной выше ситуации я обнаружил, что библиотека jquery.inherit может это сделать, мне просто интересно, может ли этого достичь отсутствие использования библиотеки.PS3:Или я неправильно понимаю.Поскольку javascript не предназначен для имитации ООП (вот почему я называю это взломом), какова "ПРАВИЛЬНАЯ" логика для реализации этого?

Это было полезно?

Решение

Это не взломать как таковой;JavaScript - это прототипированный язык, как определено Википедия как и где:

..классы отсутствуют, и повторное использование поведения (известное как наследование в языках, основанных на классах) выполняется посредством процесса клонирования существующих объектов, которые служат прототипами.

Как говорится, классы не используются в JavaScript;каждый объект, который вы создаете, является потомком JavaScript Object;все объекты в JavaScript имеют prototype object и все экземпляры объектов, которые вы создаете, "наследуют" методы и свойства от объекта-прототипа их объекта.Взгляните на MDC прототип ссылка на объект для получения дополнительной информации.

Начиная с этого момента, когда вы вызываете линию:

CHILDClass.prototype = new PARENTClass();

Это позволяет CHILDClass объект для добавления методов и свойств к своему объекту-прототипу из PARENTClass объект, который создает эффект, аналогичный идее наследования, присутствующей в языках, основанных на классах.С тех пор, как prototype object влияет на каждый экземпляр, созданный этим объектом, это позволяет методам и свойствам родительского объекта присутствовать в каждом экземпляре вашего дочернего объекта.

Если вы хотите вызвать конструктор вашего родительского класса в конструкторе вашего дочернего класса, вы используете JavaScript call функция;это позволяет вам вызывать конструктор родительского класса в контексте конструктора дочернего класса, таким образом устанавливая для вновь созданных прототипов свойств в вашем дочернем классе те же значения, что и в родительском классе.

Вам также не нужно ничего помещать туда, где вы указали *1, поскольку эта строка просто используется для добавления методов и свойств к объекту прототипа дочернего класса;однако имейте в виду, что он вызывает конструктор родительского класса, поэтому, если есть какие-либо аргументы, которые являются фундаментальными в работе конструктора родительского класса, вы должны проверить, присутствуют ли они, чтобы избежать ошибок JavaScript.

Другие советы

Вы можете вручную вызвать родительский конструктор в конструкторе подкласса следующим образом:

CHILDClass = function (basevar) {
  PARENTClass.call(this, basevar);
  // do something;
};

Хитрость здесь заключается в использовании call метод, который позволяет вам вызывать метод в контексте другого объекта.Видишь документация по call для получения более подробной информации.

JavaScript не имеет встроенной поддержки иерархий наследования, поскольку расширение типа должно выполняться посредством агрегации, т. е. добавления желаемой функциональности непосредственно к самому объекту или его прототипу, если свойство должно быть общим для экземпляров.

Тем не менее, JS достаточно мощный, чтобы сделать возможной реализацию других форм построения объектов, включая классическое наследование.

Учитывая, что функция клонирования - этого достаточно, чтобы добавить "истинное" прототипическое наследование, а не его ублюдочную обработку JavaScript - ваш пример может быть реализован следующим образом:

function ParentClass(baseVar) {
    // do stuff
}

// don't overwrite the prototype object if you want to keep `constructor`
// see http://joost.zeekat.nl/constructors-considered-mildly-confusing.html
ParentClass.prototype.a = 'b';
ParentClass.prototype.c = 'd';

function ChildClass(childVar) {
    // call the super constructor
    ParentClass.call(this, childVar);
}

// don't inherit from a ParentClass instance, but the actual prototype
ChildClass.prototype = clone(ParentClass.prototype);
ChildClass.prototype.e = 'f';

Также можно добавить немного синтаксического сахара для наследования на основе классов - моя собственная реализация можно найти здесь.

Тогда приведенный выше пример будет выглядеть следующим образом

var ParentClass = Class.extend({
    constructor: function(baseVar) {
        // do stuff
    },
    a: 'b',
    c: 'd'
});

var ChildClass = ParentClass.extend({
    e: 'f'
});

У меня есть облегченная оболочка javascript для ООП, которая обеспечивает "классовое" наследование, где вы можете переопределять базовые методы или вызывать базовые конструкторы или члены.

Вы определяете свои классы следующим образом:

//Define the 'Cat' class
function Cat(catType, firstName, lastName)
{
    //Call the 'Animal' constructor.
    Cat.$baseNew.call(this, firstName, lastName);

    this.catType = catType;
}
//Extend Animal, and Register the 'Cat' type.
Cat.extend(Animal, { type: 'Cat' }, {
    hello: function(text)
    {
        return "meaoow: " + text;
    },
    getFullName: function()
    {
        //Call the base 'Animal' getFullName method.
        return this.catType + ": " + Cat.$base.getFullName.call(this);
    }
})

//It has a built-in type system that lets you do stuff like:

var cat = new Cat("ginger", "kitty", "kat");
Cat.getType()                     // "Cat"
cat.getBaseTypesAndSelf()         // ["Cat","Animal","Class"]
cat.getType()                     // "Cat"
cat.isTypeOf(Animal.getType())    // "True"

var dynamicCat = Class.createNew("Cat", ["tab","fat","cat"])
dynamicCat.getBaseTypesAndSelf()  // ["Cat","Animal","Class"]
dynamicCat.getFullName()          // tab: fat cat

исходный код доступен по адресу: Class.js

У меня также есть более подробная информация в моем блоге о ООП в javascript

Просто подумал, что стоит упомянуть некоторые проблемы с классическим шаблоном, к которому вы стремитесь:

  1. Ссылочные переменные для суперкласса (ов) будут доступны по существу как статические данные во ВСЕХ экземплярах.Например, если у вас есть var arr = [1,2,3] в super, и вы выполняете instance_1.arr.push(4) instance_2.arr.push(5), ВСЕ эти экземпляры "увидят" изменения.
  2. Итак, вы решаете 1.с решением Аймана, которое Закас называет "Кражей конструктора", но теперь вы вызываете конструктор дважды:один раз за ваш прототип и один раз за кражу конструктора.Решение - для вашего прототипа используйте помощник, такой как inheritPrototype (я показал всю реализацию этого в этом посте: Метод inheritPrototype наследования FWIW, это, по сути, взято из комбинации страницы 181 книги Закаса и какого-то исследования Крокфорда.

  3. Никакой конфиденциальности (но опять же, вам нужно будет использовать что-то вроде шаблона прочного объекта, чтобы получить это, и это может быть не то, что вы хотите)

  4. Определение объекта остается "подвешенным":Решение - поместите оператор if, проверяющий любую из функций вашего прототипа, а затем определите прототип с помощью литерала прототипа.

У меня есть запущенные примеры всего этого на github!!!

Для меня было таким же испытанием по-настоящему насладиться обоими:Книги Закаса и Крокфорда о создании объектов и наследовании.Мне также нужно было попробовать несколько различных фреймворков TDD на JavaScript.Поэтому я решил написать эссе как о TDD-фреймворках, так и о создании и наследовании объектов JavaScript.В нем есть запущенный код и тесты jspec!Вот ссылка:* Мое Эссе / Книга с открытым исходным кодом на GitHub

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top