Когда возникла бы потребность использовать класс, объявленный таким способом, мы могли бы просто добавлять пространство имен при ссылке на конструктор:
var s = new sets.SingletonSet(1);
Автор модуля не может заранее знать, с какими другими модулями будет использоваться его модуль, поэтому он должен принять все меры против конфликтов, используя подобные пространства имен. Однако программист, использующий модуль, знает, какие модули он использует и какие имена в
них определяются. Этот программист не обязан использовать имеющиеся пространства имен ограниченно и может импортировать часто используемые значения в глобальное пространство имен. Программист, который собирается часто использовать класс
Set
из пространства имен
sets
, мог бы импортировать класс, как показано ниже:
var Set = sets.Set; // Импортировать Set в глобальное пространство имен
var s = new Set(1,2,3); // Теперь его можно использовать без префикса sets.
Иногда авторы модулей используют глубоко вложенные пространства имен. Если модуль с определениями классов множеств является частью обширной коллекции модулей, для него может использоваться пространство имен
collections
,
sets
, а сам модуль может начинаться со следующих определений:
var collections; // Объявить (или повторно объявить) глобальную переменную
if (!collections) // Если объект еще не существует
collections = {}; // Создать объект пространства имен верхнего уровня
collections.sets = {} //И внутри него создать пространство имен sets.
// Теперь определить классы множеств внутри
collections.sets
collections.sets.AbstractSet = function { ... }
Иногда пространство имен верхнего уровня используется для идентификации разработчика или организации - автора модуля и для предотвращения конфликтов между пространствами имен. Например, библиотека Google Closure определяет свой класс
Set
в пространстве имен
goog.structs
. Для определения глобально уникальных префиксов, которые едва ли будут использоваться другими авторами модулей, индивидуальные разработчики могут использовать компоненты доменного имени. Поскольку мой вебсайт имеет имя
davidflanagan.com
, я мог бы поместить свой модуль с классами множеств в пространство имен
com.davidflanagan.collections.sets
.
При таких длинных именах для любого пользователя вашего модуля операция импортирования становится особенно важной. Однако, вместо того чтобы импортировать имена отдельных классов, программист мог бы импортировать в глобальное пространство имен весь модуль целиком:
var sets = com.davidflanagan.collections.sets;
В соответствии с соглашениями имя файла модуля должно совпадать с его пространством имен. Модуль
sets
должен храниться в файле с именем
sets.js
. Если модуль использует пространство имен
collections.sets
, то этот файл должен храниться в каталоге collections/ (этот каталог мог бы также включать файл maps.js). А модуль, использующий
пространство имен
com.davidflanagan.collections.sets
, должен храниться в файле com/davidflanagan/collections/sets.js.
9.9.2. Область видимости функции как частное пространство имен
Модули имеют экспортируемый ими общедоступный прикладной интерфейс (API): это функции, классы, свойства и методы, предназначенные для использования другими программистами. Однако зачастую для внутренних нужд модуля требуются дополнительные функции или методы, которые не предназначены для использования за пределами модуля. Примером может служить функция
Set._v2s
из примера 9.6 - для нас было бы нежелательно, чтобы пользователи класса
Set
вызывали эту функцию, поэтому было бы неплохо сделать ее недоступной извне.
Этого можно добиться, определив модуль (в данном случае класс
Set
) внутри функции. Как описывалось в разделе 8.5, переменные и функции, объявленные внутри другой функции, являются локальными по отношению к этой функции и недоступны извне. Таким образом, область видимости функции (называемой иногда «функцией модуля») можно использовать как частное пространство имен модуля. Пример 9.24 демонстрирует, как это может выглядеть применительно к нашему классу
Set
.
Пример 9.24. Класс Set внутри функции модуля
// Объявляет глобальную переменную Set и присваивает ей значение, возвращаемое
// функцией. Круглые скобки, окружающие объявление функции, свидетельствуют о том,
// что функция будет вызвана сразу после ее объявления и что присваивается значение,
// возвращаемое функцией, а не сама функция. Обратите внимание, что это выражение
// определения функции, а не инструкция, поэтому наличие имени "invocation"
// не вызывает создание глобальной переменной,
var Set = (function invocation {
function Set { // Эта функция-конструктор - локальная переменная,
this.values = {}; // Свойство для хранения множества
this.n = 0; // Количество значений в множестве
this.add.apply(this, arguments); // Все аргументы являются значениями,
} // добавляемыми в множество
// Далее следуют определения методов в Set.prototype.
// Для экономии места программный код опущен
Set.prototype.contains = function(value) {
// Обратите внимание, что v2s вызывается без префикса Set._v2s