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()
return this.values.hasOwnProperty(v2s(value));
};
Set.prototype.size = function() { return this.n; };
Set.prototype.add = function() { /* ... */ };
Set.prototype.remove = function() { /* ... */ };
Set.prototype.foreach = function(f, context) {/*...*/>;
// Далее следуют вспомогательные функции и переменные, используемые
// методами выше. Они не являются частью общедоступного API модуля и скрыты
// в области видимости функции, благодаря чему не требуется объявлять их как
// свойства класса Set или использовать символ подчеркивания в качестве префикса.
function v2s(val) { /* ... */ }
function objectld(o) { /* ... */ }
var nextId = 1;
// Общедоступным API этого модуля является функция-конструктор Set().
// Нам необходимо экспортировать эту функцию за пределы частного
// пространства имен, чтобы ее можно было использовать за ее пределами.
// В данном случае конструктор экспортируется за счет передачи его
// в виде возвращаемого значения. Он становится присваиваемым значением
// в выражении в первой строке выше, return Set;
}()); // Вызвать функцию сразу после ее объявления.
Обратите внимание, что такой прием вызова функции сразу после ее определения является характерным для языка JavaScript. Программный код, выполняемый в частном пространстве имен, предваряется текстом «(function() {
» и завершается « }());
». Открывающая круглая скобка в начале сообщает интерпретатору, что это выражение определения функции, а не инструкция, поэтому в префикс можно добавить любое имя функции, поясняющее ее назначение. В примере 9.24 было использовано имя « invocation
», чтобы подчеркнуть, что функция вызывается сразу же после ее объявления. Точно так же можно было бы использовать имя « namespace
», чтобы подчеркнуть, что функция играет роль пространства имен.
Читать дальше
Конец ознакомительного отрывка
Купить книгу