Xiper

Javascript. Шаблоны проектирования. Шаблон «модуль».

Автор: Валерий Съестов Дата публикации:

Шаблон «модуль» получил широкое распространение благодаря предоставляемой им возможности структурировать и организовать программный код по мере увеличения его объема.

В отличие от других языков, в JavaScript отсутствует специальная синтаксическая конструкция для создания пакетов, но шаблон «модуль» обеспечивает все необходимое для создания независимых фрагментов программного кода, которые можно рассматривать как «черные ящики» и добавлять, заменять или удалять их из своей программы в соответствии с потребностями (возможно, изменяющимися с течением времени) вашей программы.

Шаблон «модуль», удобно использовать совместно с описанной ранее конструкцией создания пространства имен.

MYAPP.namespace("MYAPP.modules.array");
MYAPP.modules.array = (function () {
	return {
		// будет реализовано позже
}
}());

Затем можно добавить общедоступные методы:

MYAPP.modules.array = (function () {
	return {
		inArray: function (needle, hayStack) {
			// ...
},
isArray: function (a) {
	// … 
}
}
}());

В частной области видимости, образуемой немедленно вызываемой функцией, можно объявить частные свойства и методы, если это необходимо.

Окончательный результат - объект, возвращаемый немедленно вызываемой функцией, содержащий общедоступные члены модуля:

MYAPP.namespace("MYAPP.utilities.array"); 
MYAPP.utilities.array = (function () { 
// зависимости 
var uobj = MYAPP.utilities.object, 
        ulang = MYAPP.utilities.lang, 
// частные свойства 
array_string = "[object Array]", 
ops = Object.prototype.toString; 
// частные методы 
// ... 
// конец инструкции var 
// реализация необязательной процедуры инициализации 
// ... 
// общедоступные члены 
return { 
inArray: function (needle, haystack) { 
for (var i = 0, max = haystack.length; i < max; i += 1) { 
if (haystack[i] === needle) { 
return true; 
} 
}
} ,
isArray: function (а) { 
return ops.call(a) === array_string; 
} 
// … другие методы и свойства 
}; 
}()); 

Шаблон «модуль» широко используется на практике и является рекомендуемым способом организации программного кода, особенно по мере увеличения его объема.

Модули, создающие конструкторы

В предыдущем примере создается объект MYAPP.utilities.array, но иногда гораздо удобнее создавать объекты с помощью конструкторов. Для этой цели также можно использовать шаблон «модуль». Единственное отличие состоит в том, что немедленно вызываемая функция, обертывающая модуль, возвращает функцию, а не объект.

Взгляните на следующий пример использования шаблона «модуль», который создает функцию-конструктор MYAPP.utilities. Array:

MYAPP.namespace("MYAPP.modules.Array"); 
MYAPP.modules.Array = (function () { 
// зависимости 
var uobj = MYAPP.modules.object, 
        ulang = MYAPP.modules.lang, 
       // частные свойства и методы... 
       Constr; 
      // конец инструкции var 
// реализация необязательной процедуры инициализации 
// ... 
// общедоступные методы -- конструктор 
Constr = function (о) { 
this.elements = this.toArray(o); 
}; 
// общедоступные методы -- прототип 
Constr.prototype = { 
constructor: MYAPP.utilities.Array, 
version: "2.0", 
toArray: function (obj) { 
for (var i = 0, a = [], len = obj.length; i < len; i += 1) { 
a[i] = obj[i]; 
} 
return a; 
} 
}; 
// вернуть конструктор, 
// создающий новое пространство имен 
return Constr; 
}()); 

Импортирование глобальных переменных в модули

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

Функции можно передавать любые значения, но на практике ей обычно передаются ссылки на глобальные переменные и иногда даже сам глобальный объект.

Импортирование глобальных переменных позволяет увеличить скорость разрешения глобальных имен внутри немедленно вызываемой функции благодаря тому, что импортируемые переменные становятся локальными для этой функции:

MYAPP.modules.module = (function (арр, global) { 
// ссылки на объект global 
// и на глобальное пространство имен арр 
// теперь будут локальными переменными 
}(MYAPP, this));