return names.indexOf(name);
};
})(this.weekDay = {});
console.log(weekDay.name(weekDay.number("Четверг")));
// → Четверг
Отсоединяемся от глобальной области видимости
Такой шаблон часто используется в модулях JavaScript, предназначающихся для браузера. Модуль возьмёт одну глобальную переменную и обернёт свой код в функцию, чтобы у него было своё личное пространство имён. Но с этим шаблоном бывают проблемы, когда много модулей требуют одно и то же имя, или когда вам надо загрузить две версии модуля одновременно.
Подкрутив кое-что, мы можем сделать систему, разрешающую одному модулю обращаться к интерфейсному объекту другого, без выхода в глобальную ОВ. Наша цель – функция require
Этот подход решает проблемы, упомянутые ранее, и у него есть ещё одно преимущество – зависимости вашей программы становятся явными, и поэтому сложнее случайно вызвать ненужный вам модуль без чёткого его объявления.
Нам понадобятся две вещи. Во-первых, функция readFile
Выполняем данные как код
Есть несколько способов получить данные (строку кода) и выполнить их как часть текущей программы.
Самый очевидный – оператор eval
function evalAndReturnX(code) {
eval(code);
return x;
}
console.log(evalAndReturnX("var x = 2"));
// → 2
Способ лучше – использовать конструктор Function
var plusOne = new Function("n", "return n + 1;");
console.log(plusOne(4));
// → 5
Это то, что нам надо. Мы обернём код модуля в функцию, и её область видимости станет областью видимости нашего модуля.
Require
Вот минимальная версия функции require
function require(name) {
var code = new Function("exports", readFile(name));
var exports = {};
code(exports);
return exports;
}
console.log(require("weekDay").name(1));
// → Вторник
Так как конструктор new Function
exports является аргументом функции модуля, модулю не нужно его объявлять. Это убирает много мусора из нашего модуля-примера.var names = ["Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота", "Воскресенье"];
exports.name = function(number) {
return names[number];
};
exports.number = function(name) {
return names.indexOf(name);
};
При использовании такого шаблона модуль обычно начинается с объявления нескольких переменных, которые загружают модули, от которых он зависит.
var weekDay = require("weekDay");
var today = require("today");
console.log(weekDay.name(today.dayNumber()));
У такого простого варианта require
require – если у нескольких модулей есть одинаковые зависимости, или вызов require находится внутри функции, которая вызывается многократно, будет потеряно время и энергия.Это можно решить, храня уже загруженные модули в объекте, и возвращая существующее значение, когда он грузится несколько раз.
Вторая проблема – модуль не может экспортировать переменную напрямую, только через объект export
require всегда использует объект exports в качестве возвращаемого значения.