Опубликованные в JavaScript модули — наиболее часто используемые шаблоны, которые применяются для обеспечения независимости отдельных фрагментов кода от других компонентов. Это создает слабую связанность, необходимую для поддержки хорошо структурированного кода.
Если вы знакомы с объектно-ориентированными языками, вы знаете, что модули — это «классы» JavaScript. Одним из многих преимуществ классов является инкапсуляция — предотвращение доступа других классов к состоянию и поведению. Шаблон модуля допускает публичный и частный (плюс малоизвестные защищенный и привилегированный) уровни доступа.
Модули должны быть IIFE (мгновенно выполняющимися функциями-выражениями), чтобы разрешить частные области видимости, и в том числе замыкание, защищающее переменные и методы (однако оно будет возвращать объект вместо функции). Вот как это выглядит:
(function() { // declare private variables and/or functions return { // declare public variables and/or functions } })();
Здесь мы создаем частные переменные и/или функции перед возвратом объекта, который нам нужен. Код за пределами закрытой скобки не сможет получить доступ к этим переменным, поскольку он не находится в той же области. Возьмем, к примеру, более конкретную реализацию:
var HTMLChanger = (function() { var contents = 'contents' var changeHTML = function() { var element = document.getElementById('attribute-to-change'); element.innerHTML = contents; } return { callChangeHTML: function() { changeHTML(); console.log(contents); } }; })(); HTMLChanger.callChangeHTML(); // Outputs: 'contents' console.log(HTMLChanger.contents); // undefined
Обратите внимание, что callChangeHTML привязывается к возвращаемому объекту, и на него можно ссылаться в пространстве имен HTMLChanger. Однако за пределами модуля на данный контент ссылаться нельзя.
Выявляющий модульный шаблон
Выявляющий модульный шаблон — это вариация модульного шаблона. Цель его состоит в том, чтобы поддерживать инкапсуляцию и раскрывать определенные переменные и методы, возвращаемые в литерале объекта. Прямая реализация этого метода выглядит так:
var Exposer = (function() { var privateVariable = 10; var privateMethod = function() { console.log('Inside a private method!'); privateVariable++; } var methodToExpose = function() { console.log('This is a method I want to expose!'); } var otherMethodIWantToExpose = function() { privateMethod(); } return { first: methodToExpose, second: otherMethodIWantToExpose }; })(); Exposer.first(); // Output: This is a method I want to expose! Exposer.second(); // Output: Inside a private method! Exposer.methodToExpose; // undefined
Он выглядит намного чище, однако у него есть очевидный недостаток — невозможность ссылаться на частные методы, что может создать проблемы во время тестирования. Кроме того, вы не можете переопределить публичное поведение.
Читайте также: Шаблоны проектирования JavaScript: наблюдатель