Для начала ознакомьтесь с Паттерн «Модуль» #1.
Вариации шаблона «Модуль»
Import миксины
Эта вариация паттерна демонстрирует, как глобальные переменные (напр., JQuery , Underscore) могут быть переданы в качестве аргументов анонимной функции нашего модуля. Это фактически позволяет нам импортировать их и называть как хотим.
// Глобальный модуль
var myModule = (function ( jQ, _ ) {
function privateMethod1(){
jQ(".container").html("test");
}
function privateMethod2(){
console.log( _.min([10, 5, 100, 2, 1000]) );
}
return{
publicMethod: function(){
privateMethod1();
}
};
// Pull in jQuery и Underscore
})( jQuery, _ );
myModule.publicMethod();
Экспорт
Следующая вариация позволяет объявить глобальные переменные без их использования, и может также поддержать концепцию глобального импорта, что видно в последнем примере.
// Глобальный модуль
var myModule = (function () {
// Module object
var module = {},
privateVariable = "Hello World";
function privateMethod() {
// ...
}
module.publicProperty = "Foobar";
module.publicMethod = function () {
console.log( privateVariable );
};
return module;
})();
Реализация «модуля» в различных библиотеках и фреймворках.
Dojo
Dojo это удобный метод работы с объектами под названием dojo.setObject(). Он принимает в качестве первого аргумента строку, разделенную точками, такую как myObj.parent.child, которая ссылается на свойство под названием «child» в пределах объекта «parent» , определенного внутри «MyObj » . Использование setObject() позволяет установить значение «детей«, создавая любого из промежуточных объектов в остальной части пути, если таковые не существуют.
Например, если мы хотим объявить basket.core как объект namespace store, то это может быть достигнуто следующим образом:
var store = window.store || {};
if ( !store["basket"] ) {
store.basket = {};
}
if ( !store.basket["core"] ) {
store.basket.core = {};
}
store.basket.core = {
// ...остальная логика
};
Или следующим образом с помощью Dojo 1.7 ( AMD — совместимая версия) и выше :
require(["dojo/_base/customStore"], function( store ){
// используем dojo.setObject()
store.setObject( "basket.core", (function() {
var basket = [];
function privateMethod() {
console.log(basket);
}
return {
publicMethod: function(){
privateMethod();
}
};
})());
});
Для получения дополнительной информации dojo.setObject() смотрите официальную документацию.
ExtJS
Для тех, кто использует Sencha’s ExtJS, смотрите пример ниже, он показывает, как правильно использовать паттерн «модуль» с фреймворком.
В примере ниже мы видим как определить пространство имен (namespace), которое затем может быть заполнено модулем, содержащим частный и публичный API. За исключением некоторых семантических различий, это похоже на то, как паттерн «Модуль» реализуется в чистом (vanilla) JavaScript :
// создаем namespace
Ext.namespace("myNameSpace");
// создаем приложение
myNameSpace.app = function () {
// отсюда не имеется доступ к DOM ; элементы еще не существуют
// приватные переменные
var btn1,
privVar1 = 11;
// приватные функции
var btn1Handler = function ( button, event ) {
console.log( "privVar1=" + privVar1 );
console.log( "this.btn1Text=" + this.btn1Text );
};
// публичное space
return {
// публичные свойства,напр,. строки для перевода
btn1Text: "Button 1",
// публичные методы
init: function () {
if ( Ext.Ext2 ) {
btn1 = new Ext.Button({
renderTo: "btn1-ct",
text: this.btn1Text,
handler: btn1Handler
});
} else {
btn1 = new Ext.Button( "btn1-ct", {
text: this.btn1Text,
handler: btn1Handler
});
}
}
};
}();
YUI
Кроме того, мы также можем реализовать паттерн «Модуль» при создании приложений с использованием YUI3 . Следующий пример основывается на паттерне «Модуля» во фреймворке YUI, реализованном Эриком Миргалия, но опять же, не сильно отличающимся от версии vanilla JavaScript:
Y.namespace( "store.basket" ) ;
Y.store.basket = (function () {
var myPrivateVar, myPrivateMethod;
// приватные переменные:
myPrivateVar = "I can be accessed only within Y.store.basket.";
// приватный метод:
myPrivateMethod = function () {
Y.log( "I can be accessed only from within YAHOO.store.basket" );
}
return {
myPublicProperty: "I'm a public property.",
myPublicMethod: function () {
Y.log( "I'm a public method." );
// Внутри корзины я могу получить доступ к приавтаным переменным и методам:
Y.log( myPrivateVar );
Y.log( myPrivateMethod() );
// The native scope of myPublicMethod сохранен
// поэтому у нас есть доступ к this:
Y.log( this.myPublicProperty );
}
};
})();
jQuery
Существует множество способов представить jQuery код в виде паттерна «модуль», даже если этот код не напоминает привычные jQuery плагины. Бен Черри ранее предлагал способ, при котором, если у модулей имеются общие черты, то они объявляются через функцию-обертку.
В следующем примере функция library используется для объявления новой библиотеки и при создании новой библиотеки (т.е. модуля) автоматически связывает функцию library с document.ready.
Y.namespace( "store.basket" ) ;
Y.store.basket = (function () {
var myPrivateVar, myPrivateMethod;
// приватные переменные:
myPrivateVar = "I can be accessed only within Y.store.basket.";
// приватный метод:
myPrivateMethod = function () {
Y.log( "I can be accessed only from within YAHOO.store.basket" );
}
return {
myPublicProperty: "I'm a public property.",
myPublicMethod: function () {
Y.log( "I'm a public method." );
// Внутри корзины я могу получить доступ к приавтаным переменным и методам:
Y.log( myPrivateVar );
Y.log( myPrivateMethod() );
// The native scope of myPublicMethod сохранен
// поэтому у нас есть доступ к this:
Y.log( this.myPublicProperty );
}
};
})();
Преимущества
Чем же хорош шаблон «Модуль»? Во-первых, он понятен разработчикам, переходящих с объектно-ориентированного программирования.
Во-вторых, он поддерживает приватные данные – так, в паттерне «Модуль» публичные части нашего кода могут дотянуться до приватных частей, однако извне мы не можем достать приватные части класса.
Недостатки
К недостаткам шаблона «Модуль» относится следующее: доступ, как к публичным, так и приватным элементам, когда мы хотим изменить видимость, на самом деле мы должны внести изменения в каждое место используемого элемента.
Мы также не можем получить доступ к частным элементам в методах, которые добавляются к объекту на более позднем этапе. Тем не менее, во многих случаях паттерн «Модуль» по-прежнему полезен и при правильном использовании имеет потенциал улучшить структуру нашего приложения.
Другие недостатки — неспособность создавать автоматизированные модульные тесты для приватных элементов, также есть дополнительные сложности, ошибки, требующие исправлений.
Источник: addyosmani.com