Skip to content
Grigoriev Oleg edited this page Mar 25, 2013 · 4 revisions

go.Class: множественное наследование

Зачем

Зачем нужно множественное наследование в JS? Затем же, зачем и в других языках.

Один из распространённых случаев: когда классам из различных ветвей иерархии приходится выполнять сходные действия.

В качестве примеров классов для множественного наследования, можно рассмотреть классы из модуля go.Ext.

Как

Нужно передать в go.Class аргументом не родительский класс, а массив родительских классов.

var OneClass = go.Class({ /* ... */ }),
    TwoClass = go.Class({ /* ... */ }),
    ThreeClass = go.Class({ /* ... */ }),
    
    ChildClass = go.Class([OneClass, TwoClass, ThreeClass], {
        // ...
    });

В примере ChildClass наследуется сразу от 3-х классов.

При наличии одноимённых методов в нескольких родительских классах, в дочерний класс попадает метод из класса объявленного в списке раньше других.

Реализация

Так как JavaScript не позволяет создавать множественное наследование через прототипы, то здесь происходит следующее:

  • Класс, указанный первым, является "основным" предком. Он используется для наследования через цепочку прототипов.
  • Остальные классы из списка являются "дополнительными". Их свойства и методы просто копируются в прототип дочернего класса (если там ещё нет одноимённых).

Таким образом, с теоретической точки зрения, за место класса в иерархии отвечает основной предок, а дополнительные являются скорее примесями. При этом если идеологически все предки являются примесями, то основной класс можно не указывать:

ChildClass = go.Class([null, OneClass, TwoClass, ThreeClass], {
    // ...
});

В этом случае основным будет базовый класс go.Class.Root.

"Неклассы" в роли предков

Так как дополнительные классы предназначены только для копирования из них свойств и методов, то в их качестве можно использовать не только классы порождённые через go.Class, но и простые объекты или функции-конструкторы (будет использован их прототип):

var methods = {
    'method' : function () {
        return "method";
    }
};

var ChildClass = go.Class([ParentClass, methods], {});

instanceof

Так как дополнительные классы не попадают в цепочки прототипов дочернего, то instanceof для них не работает.

var instance = ChildClass();

instance instanceof ChildClass; // true
instance instanceof OneClass;   // true
instance instanceof TwoClass;   // false
instance instanceof ThreeClass; // false

Следует использовать метод instance_of():

var instance = ChildClass();

instance.instance_of(ChildClass); // true
instance.instance_of(OneClass);   // true
instance.instance_of(TwoClass);   // true
instance.instance_of(ThreeClass); // true

Для классов же isSubclassOf():

ChildClass.isSubclassOf(OneClass);   // true
ChildClass.isSubclassOf(TwoClass);   // true
ChildClass.isSubclassOf(ThreeClass); // true

ThreeClass.isSubclassOf(ChildClass); // false
Clone this wiki locally