Чтение онлайн

ЖАНРЫ

JavaScript. Подробное руководство, 6-е издание
Шрифт:

SetFromArray.prototype = Set.prototype;

var s = new SetFromArray([1,2,3]);

s instanceof Set // => true

В ECMAScript 5 функции имеют метод

bind,
особенности которого позволяют создавать подобные вспомогательные конструкторы (раздел 8.7.4).

9.7. Подклассы

В объектно-ориентированном программировании класс В может расширять, или наследовать, другой класс А. Класс А в этом случае называется суперклассом, а класс В - подклассом. Экземпляры класса В наследуют все методы экземпляров

класса А. Класс В может определять собственные методы экземпляров, некоторые из которых могут переопределять методы класса А с теми же именами. Если метод класса В переопределяет метод класса А, переопределяющий метод класса В может вызывать переопределенный метод класса А: этот прием называется вызовом метода базового класса. Аналогично конструктор В подкласса может вызывать конструктор А суперкласса. Это называется вызовом конструктора базового класса. Подклассы сами могут наследоваться другими подклассами и, работая над созданием иерархии классов, иногда бывает полезно определять абстрактные классы. Абстрактный класс - это класс, в котором объявляется один или более методов без реализации. Реализация таких абстрактных методов возлагается на конкретные подклассы абстрактного класса.

Ключом к созданию подклассов в языке JavaScript является корректная инициализация объекта-прототипа. Если класс В расширяет класс А, то объект В.prototype должен наследовать

A.prototype
. В этом случае экземпляры класса В будут наследовать свойства от объекта
В.prototype
, который в свою очередь наследует свойства от
A.prototype
. В этом разделе демонстрируются все представленные выше термины, связанные с подклассами, а также рассматривается прием, альтернативный наследованию, который называется композицией.

Используя в качестве основы класс

Set
из примера 9.6, этот раздел продемонстрирует, как определять подклассы, как вызывать конструкторы базовых классов и переопределенные методы, как вместо наследования использовать прием композиции и, наконец, как отделять интерфейсы от реализации с помощью абстрактных классов. Этот раздел завершает расширенный пример, в котором определяется иерархия классов
Set
. Следует отметить, что первые примеры в этом разделе служат цели продемонстрировать основные приемы использования механизма наследования, и некоторые из них имеют существенные недостатки, которые будут обсуждаться далее в этом же разделе.

9.7.1. Определение подкласса

В языке JavaScript объекты наследуют свойства (обычно методы) от объекта-прототипа своего класса. Если объект

O
является экземпляром класса
В
, а класс
В
является подклассом класса
А
, то объект
O
также наследует свойства класса
А
. Добиться этого можно за счет наследования объектом-прототипом класса
В
свойств объекта-прототипа класса
А
, как показано ниже, с использованием функции
inherit
(пример 6.1):

В.prototype = inherit(A.prototype); // Подкласс наследует суперкласс

В.prototype.constructor = В; // Переопределить унаследованное св. constructor

Эти две строки являются ключом к созданию подклассов в JavaScript. Без них объект-прототип будет обычным объектом - объектом, наследующим свойства от

Object.prototype
, - а это означает, что класс будет подклассом класса
Object
, подобно всем остальным классам. Если добавить эти две строки в функцию
defineClass
(раздел 9.3),
ее можно будет преобразовать в функцию
defineSubclass
и в метод
Function.prototype.extend,
как показано в примере 9.11.

Пример 9.11. Вспомогательные инструменты определения подклассов

// Простая функция для создания простых подклассов

function defineSubclass(superclass, // Конструктор суперкласса

constructor, // Конструктор нового подкласса

methods, // Методы экземпл.: копируются в прототип

statics) // Свойства класса: копируются в констр-р

{

// Установить объект-прототип подкласса

constructor.prototype = inherit(superclass.prototype);

constructor.prototype.constructor = constructor;

// Скопировать методы methods и statics, как в случае с обычными классами

if (methods) extend(constructor.prototype, methods);

if (statics) extend(constructor, statics);

// Вернуть класс

return constructor;

}

// To же самое можно реализовать в виде метода конструктора суперкласса

Function.prototype.extend = function(constructor, methods, statics) {

return defineSubclass(this, constructor, methods, statics);

};

Пример 9.12 демонстрирует, как определить подкласс «вручную», без использования функции def ineSubclass. В этом примере определяется подкласс SingletonSet класса Set. Класс SingletonSet представляет специализированное множество, доступное только для чтения и состоящее из единственного постоянно элемента.

Пример 9.12. SingletonSet: простой подкласс множеств

// Функция-конструктор

function SingletonSet(member) {

this.member = member; // Сохранить единственный элемент множества

}

// Создает объект-прототип, наследующий объект-прототип класса Set.

SingletonSet.prototype = inherit(Set.prototype);

// Далее добавляются свойства в прототип.

// Эти свойства переопределяют одноименные свойства объекта

Set.prototype. extend(SingletonSet.prototype, {

// Установить свойство constructor

constructor: SingletonSet,

// Данное множество доступно только для чтения: методы add и remove

// возбуждают исключение

Поделиться с друзьями: