Выбрать главу

Классы в языке JavaScript основаны на использовании механизма наследования прототипов. Если два объекта наследуют свойства от одного и того же объекта-прототипа, говорят, что они принадлежат одному классу. С прототипами и наследованием мы познакомились в разделах 6.1.3 и 6.2.2. Сведения из этих разделов вам обязательно потребуются для понимания того, о чем рассказывается в этой главе. В этой главе прототипы будут рассматриваться в разделе 9.1.

Если два объекта наследуют один и тот же прототип, обычно (но не обязательно) это означает, что они были созданы и инициализированы с помощью одного конструктора. С конструкторами мы познакомились в разделах 4.6, 6.1.2 и 8.2.3. Дополнительные сведения о них в этой главе приводятся в разделе 9.2.

Те, кто знаком со строго типизированными объектно-ориентированными языками программирования, такими как Java или C++, могут заметить, что классы в языке JavaScript совершенно не похожи на классы в этих языках. Конечно, есть некоторые синтаксические сходства, и имеется возможность имитировать многие особенности «классических» классов в JavaScript. Но лучше будет с самого начала понять, что классы и механизм наследования на основе прототипов в языке JavaScript существенно отличаются от классов и механизма наследования на основе классов в языке Java и подобных ему. В разделе 9.3 демонстрируются приемы имитации классических классов на языке JavaScript.

Еще одной важной особенностью классов в языке JavaScript является возможность динамического расширения. Эта особенность описывается в разделе 9.4. Классы можно также интерпретировать как типы данных, и в разделе 9.5 будет представлено несколько способов определения класса объекта. В этом разделе вы также познакомитесь с философией программирования, известной как «утиная типизация» («duck-typing»), которая во главу угла ставит не тип объекта, а его возможности.

После знакомства со всеми этими основами объектно-ориентированного программирования в JavaScript мы перейдем в этой же главе к изучению более практического материала. В разделе 9.6 будут представлены два примера непростых классов и продемонстрировано несколько практических объектно-ориентированных приемов расширения этих классов. В разделе 9.7 будет показано (на множестве примеров), как расширять или наследовать другие классы и как создавать иерархии классов в языке JavaScript. В разделе 9.8 рассматриваются дополнительные приемы работы с классами с использованием новых возможностей, появившихся в ECMAScript 5.

Определение классов - это один из способов создания модульного программного кода многократного использования. В последнем разделе этой главы мы в общих чертах поговорим о модулях в языке JavaScript.

9.1. Классы и прототипы

В языке JavaScript класс - это множество объектов, наследующих свойства от общего объекта-прототипа. Таким образом, объект-прототип является центральной особенностью класса. В примере 6.1 была определена функция inherit(), возвращающая вновь созданный объект, наследующий указанный объект-прототип. Если определить объект-прототип и затем воспользоваться функцией inherit() для создания объектов, наследующих его, фактически будет создан класс JavaScript. Обычно экземпляры класса требуют дополнительной инициализации, поэтому обычно определяется функция, которая создает и инициализирует новые объекты. В примере 9.1 демонстрируется такая функция: она определяет объект-прототип класса, представляющего диапазон значений, а также «фабричную» функцию, которая создает и инициализирует новые экземпляры класса.

Пример 9.1. Простой класс JavaScript

// range.js: Класс, представляющий диапазон значений.

// Это фабричная функция, которая возвращает новый объект range,

function range(from, to) {

  // Использует функцию inherit() для создания объекта, наследующего объект-прототип,

  // определяемый ниже. Объект-прототип хранится как свойство данной функции