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

Иногда авторы модулей используют глубоко вложенные пространства имен. Если модуль с определениями классов множеств является частью обширной коллекции модулей, для него может использоваться пространство имен

<b>collections</b>
,
<b>sets</b>
, а сам модуль может начинаться со следующих определений:

<b>var collections; // Объявить (или повторно объявить) глобальную переменную</b>

<b>if (!collections) // Если объект еще не существует</b>

<b>  collections = {}; // Создать объект пространства имен верхнего уровня</b>

<b>collections.sets = {} //И внутри него создать пространство имен sets.</b>

<b>// Теперь определить классы множеств внутри </b>
<b>collections.sets</b>

<b>collections.sets.AbstractSet = function() { ... }</b>

Иногда пространство имен верхнего уровня используется для идентификации разработчика или организации - автора модуля и для предотвращения конфликтов между пространствами имен. Например, библиотека Google Closure определяет свой класс

<b>Set</b>
в пространстве имен
<b>goog.structs</b>
. Для определения глобально уникальных префиксов, которые едва ли будут использоваться другими авторами модулей, индивидуальные разработчики могут использовать компоненты доменного имени. Поскольку мой вебсайт имеет имя
<b>davidflanagan.com</b>
, я мог бы поместить свой модуль с классами множеств в пространство имен
<b>com.davidflanagan.collections.sets</b>
.

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

<b>var sets = com.davidflanagan.collections.sets;</b>

В соответствии с соглашениями имя файла модуля должно совпадать с его пространством имен. Модуль

<b>sets</b>
должен храниться в файле с именем
<b>sets.js</b>
. Если модуль использует пространство имен
<b>collections.sets</b>
, то этот файл должен храниться в каталоге collections/ (этот каталог мог бы также включать файл maps.js). А модуль, использующий пространство имен
<b>com.davidflanagan.collections.sets</b>
, должен храниться в файле com/davidflanagan/collections/sets.js.

9.9.2. Область видимости функции как частное пространство имен

Модули имеют экспортируемый ими общедоступный прикладной интерфейс (API): это функции, классы, свойства и методы, предназначенные для использования другими программистами. Однако зачастую для внутренних нужд модуля требуются дополнительные функции или методы, которые не предназначены для использования за пределами модуля. Примером может служить функция

<b>Set._v2s()</b>
из примера 9.6 - для нас было бы нежелательно, чтобы пользователи класса
<b>Set</b>
вызывали эту функцию, поэтому было бы неплохо сделать ее недоступной извне.

Этого можно добиться, определив модуль (в данном случае класс

<b>Set</b>
) внутри функции. Как описывалось в разделе 8.5, переменные и функции, объявленные внутри другой функции, являются локальными по отношению к этой функции и недоступны извне. Таким образом, область видимости функции (называемой иногда «функцией модуля») можно использовать как частное пространство имен модуля. Пример 9.24 демонстрирует, как это может выглядеть применительно к нашему классу
<b>Set</b>
.

Пример 9.24. Класс Set внутри функции модуля

<b>// Объявляет глобальную переменную Set и присваивает ей значение, возвращаемое</b>

<b>// функцией. Круглые скобки, окружающие объявление функции, свидетельствуют о том,</b>

<b>// что функция будет вызвана сразу после ее объявления и что присваивается значение,</b>

<b>// возвращаемое функцией, а не сама функция. Обратите внимание, что это выражение</b>

<b>// определения функции, а не инструкция, поэтому наличие имени &quot;invocation&quot;</b>

<b>// не вызывает создание глобальной переменной,</b>

<b>var Set = (function invocation() {</b>

<b>  function Set() { // Эта функция-конструктор - локальная переменная,</b>

<b>    this.values = {}; // Свойство для хранения множества</b>

<b>    this.n = 0; // Количество значений в множестве</b>

<b>    this.add.apply(this, arguments); // Все аргументы являются значениями,</b>

<b>  } // добавляемыми в множество</b>

<b>  // Далее следуют определения методов в Set.prototype.</b>

<b>  // Для экономии места программный код опущен</b>

<b>  Set.prototype.contains = function(value) {</b>

<b>    // Обратите внимание, что v2s() вызывается без префикса Set._v2s()</b>

<b>    return this.values.hasOwnProperty(v2s(value));</b>

<b>  };</b>

<b>  Set.prototype.size = function() { return this.n; };</b>

<b>  Set.prototype.add = function() { /* ... */ };</b>

<b>  Set.prototype.remove = function() { /* ... */ };</b>

<b>  Set.prototype.foreach = function(f, context) {/*...*/&gt;;</b>

<b>  // Далее следуют вспомогательные функции и переменные, используемые</b>

<b>  // методами выше. Они не являются частью общедоступного API модуля и скрыты</b>

<b>  // в области видимости функции, благодаря чему не требуется объявлять их как</b>