наследование JavaScript - PullRequest
       11

наследование JavaScript

8 голосов
/ 31 мая 2009

Я знаю, что есть много подобных вопросов - это тонны отличных ответов на это. Я пытался взглянуть на классические методы наследования или методы закрытия и т. Д. Почему-то я считаю, что они являются более или менее «взломанными» методами для меня, поскольку в действительности это не то, для чего предназначен 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. Но один сценарий, который я понятия не имею, как реализовать, заключается в том, что если я захочу выполнить инициализацию создания объекта DURING (то есть внутри конструктора), и новый объект можно будет использовать сразу же ... Моя иллюстрация проблемы может не быть слишком ясным, поэтому позвольте мне использовать следующий C # Psuedo, чтобы объяснить, что я хочу сделать:

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

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

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

Ответы [ 5 ]

17 голосов
/ 31 мая 2009

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

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

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

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

CHILDClass.prototype = new PARENTClass();

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

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

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

10 голосов
/ 31 мая 2009

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

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

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

1 голос
/ 29 октября 2009

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

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

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

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

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

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

1 голос
/ 30 июля 2009

У меня есть облегченная оболочка ООП 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 голос
/ 31 мая 2009

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'
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...