Выразительный JavaScript (Хавербеке) - страница 108

, это функциональное выражение. А если инструкция начинается с >function, это объявление функции, которое требует названия, и, так как это не выражение, не может быть вызвано при помощи скобок >() после неё. Можно представлять себе заключение в скобки как трюк, чтобы функция принудительно интерпретировалась как выражение.

Объекты в качестве интерфейсов

Представьте, что нам надо добавить ещё одну функцию в наш модуль «день недели». Мы уже не можем возвращать функцию, а должны завернуть две функции в объект.

>var weekDay = function() {

>  var names = ["Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота", "Воскресенье"];

>  return {

>    name: function(number) { return names[number]; },

>    number: function(name) { return names.indexOf(name); }

>  };

>}();


>console.log(weekDay.name(weekDay.number("Воскресенье")));

>// → Воскресенье

Когда модуль большой, собирать все возвращаемые значения в объект в конце функции неудобно, потому что многие возвращаемые функции будут большими, и вам было бы удобнее их записывать где-то в другом месте, рядом со связанным с ними кодом. Удобно объявить объект (обычно называемый >exports) и добавлять к нему свойства каждый раз, когда нам надо что-то экспортировать. В следующем примере функция модуля принимает объект интерфейса как аргумент, позволяя коду снаружи функции создать его и сохранить в переменной. Снаружи функции >this ссылается на объект глобальной области видимости.

>(function(exports) {

>  var names = ["Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота", "Воскресенье"];


>  exports.name = function(number) {

>    return names[number];

>  };

>  exports.number = function(name) {

>    return names.indexOf(name);

>  };

>})(this.weekDay = {});


>console.log(weekDay.name(weekDay.number("Четверг")));

>// → Четверг

Отсоединяемся от глобальной области видимости

Такой шаблон часто используется в модулях JavaScript, предназначающихся для браузера. Модуль возьмёт одну глобальную переменную и обернёт свой код в функцию, чтобы у него было своё личное пространство имён. Но с этим шаблоном бывают проблемы, когда много модулей требуют одно и то же имя, или когда вам надо загрузить две версии модуля одновременно.

Подкрутив кое-что, мы можем сделать систему, разрешающую одному модулю обращаться к интерфейсному объекту другого, без выхода в глобальную ОВ. Наша цель – функция >require, которая, получая имя модуля, загрузит его файл (с диска или из сети, в зависимости от платформы) и вернёт соответствующее значение с интерфейсом.

Этот подход решает проблемы, упомянутые ранее, и у него есть ещё одно преимущество – зависимости вашей программы становятся явными, и поэтому сложнее случайно вызвать ненужный вам модуль без чёткого его объявления.