Автор Тема: Каноническое ООП наследование в JavaScript  (Прочитано 2459 раз)

vlad

  • Hero Member
  • *****
  • Сообщений: 1391
    • Просмотр профиля
Каноническое ООП наследование в JavaScript
« : Октябрь 10, 2012, 06:26:07 pm »
Как известно, поддержка ООП в JavaScript весьма своезобразная. Настолько своеобразная, что лучше бы такой поддержки там совсем не было (чтоб народ не смущать). К сожалению, когда дело доходит до чего-то более сложного, чем обработка кнопки на веб-страничке - без человеческого ООП трудно. Поэтому народ массово лепит фрэймворки, которые пытаются эмулировать нормальное ООП (добавляя своих проблем, как и положено фрэймворкам).

Так получилось, что в задаче возникла иерархия типов и мне потребовалось проверить принадлженость объекта типу в иерархии. Без привлечения фрэймворков, минимальный вариант на голом JavaScript. В JavaScript для этого (как и положено ООП языку) есть оператор 'instanceof'. Проблема  в том, что пользовательских типов как таковых в JavaScript нет, поэтому и "наследуются" не типы, а объекты. Если погуглить по теме, то можно (легко) найти примерно такой вариант:
function A(){} // как бы конструктор класса А

function B(){} // как бы конструктор класса Б
B.prototype = new A(); // B наследует A

var b = new B();
assert(b instanceof A);

Проблемы начинаются, когда "конструкторы" начинаются делать что-то интересное - принимать параметры, вызывать базовые конструкторы, инциализировать поля объекта. Все потому, что смешиваются в одном два понятия: объект типа  и тип объекта.
Я делал несколь попыток отделить мух от котлет - наконец заработал вот такой вариант:
function AType(){}
function BType(){}
BType.prototype = new AType(); // BType наследует AType

function A(a){this.fieldA = a;}
A.prototype = new AType(); // A - конструктор типа AType

function B(a, b)
{
    A.call(this, a); // вызов базового конструктора
    this.fieldB = b;
}
B.prototype = new BType();  // B - конструктор типа AType

var b = new B('a', 'b');
assert(b instanceof AType);
assert(b instanceof BType);
assert(b.fieldA == 'a');
assert(b.fieldB == 'b');

В гугле ничего подобного не видел, поэтому решил написать сюда и обсудить. Может кто предложит более простое/правильное решение.