В первой части этой серии статей мы обсуждали приложение Backbone.Marionette. В этот раз мы рассмотрим модульную систему, встроенную в Backbone.Marionette. Попасть к списку модулей вы можете через пункт Application
(приложение). Модули сами по себе – это довольно информативная тема, которая заслуживает подробного рассмотрения в отдельной статье.
Что такое модули?
Прежде чем мы углубимся в основные детали использования модульной системы Marionette, необходимо четко определиться со значением термина модуль. Модуль – это независимый фрагмент кода, который выполняет определенную функцию. Конкретно взятый модуль можно использовать совместно с другими модулями для создания целостной системы. Чем более независимым является фрагмент кода, тем легче его можно будет заменить или провести внутреннюю модификацию, не затрагивая другие части системы.
В этой статье мы в основном будем рассматривать идентификацию модулей. Если же вы хотите больше узнать о том, как правильно создавать модульный код, то можно воспользоваться множеством источников из интернета. Я хотел бы порекомендовать к ознакомлению главу «Удобство обслуживания зависит от модульности» из книги Подробно об одностраничных приложениях, которая к слову считается одной из лучших в своей области.
В настоящее время язык программирования JavaScript не имеет никаких встроенных функциональных инструментов для инициализации модулей (следующая версия должна обеспечить эту возможность). Однако существует множество библиотек, которые позволяют организовать инициализацию и загрузку модулей. К сожалению, модульная система Marionette не поддерживает загрузку модулей из других файлов, но с другой стороны предоставляет функциональные возможности, которых нет в других системах, например, возможность запускать и отключать модули. Позже мы рассмотрим этот вопрос более детально. Сейчас мы рассмотрим пример процесса инициализации модуля.
Инициализация модуля.
Давайте начнем с основных пунктов инициализации модуля. Как уже упоминалось, перейти к списку модулей можно через раздел Application
. Все действия мы будем подкреплять примерами. Затем мы сможем использовать команду module
для инициализации модуля.
var App = new Backbone.Marionette.Application();
var myModule = App.module(‘myModule’);
Это довольно просто, правда? Так и есть, но это всего лишь пример создания простейшего модуля. А что конкретно мы создали? По сути, мы сказали приложению, что хотим создать шаблон модуля, без добавленного нами функционала, и что он будет называться myModule
(в соответствии с аргументом, который мы передали в module
). Но что такое шаблон модуля? Это экземпляр объекта Marionette.Module
.
Module
содержит встроенные функциональные возможности, такие как обработка событий (через EventAggregator
, которые мы подробно обсудим в следующей статье), начиная с инициализаторов (как у Application
) и заканчивая финализаторами (мы рассмотрим их в разделе «Запуск и отключение модулей»).
Стандартная инициализация модуля.
Теперь давайте рассмотрим пример инициализации модуля для заданных нами функциональных требований.
App.module("myModule", function(myModule, App, Backbone, Marionette, $, _){
// Private Data And Functions
var privateData = "this is private data";
var privateFunction = function(){
console.log(privateData);}
// Public Data And Functions
myModule.someData = "public data";
myModule.someFunction = function(){
privateFunction();
console.log(myModule.someData);}
});
Как вы видите, здесь представлено много команд. Давайте посмотрим на первую строку и разберем последовательность действий. Как и раньше, мы вызываем App.module
и присваиваем имя модулю. Но теперь мы также передаем значение функции. Функция содержит несколько аргументов. Готов поспорить, вы можете определить какие именно, просто взглянув на имена, которые я им задал, но я все равно объясню:
- myModule является тем самым модулем, который вы пытаетесь создать. Помните, что он уже создан для вас, и это новый экземпляр объекта
Module
. Возможно, что вы захотите расширить его при помощи каких-то новых свойств или методов; в противном случае можно просто придерживаться краткого синтаксиса, который не требует передачи в функцию. App
— этоApplication
объект, который вызывается функциейmodule
.Backbone
— это, естественно, ссылка на Backbone библиотеку.Marionette
— это ссылка на Backbone.Marionette библиотеку. На самом деле к ней можно попасть черезBackbone
, но вы также можете создать псевдоним и сделать имя короче.$-
это ваша DOM библиотека, которая будет либо JQuery либо Zepto (или, возможно, что-то еще в будущем)._
— это ссылка на Underscore или Lodash, в зависимости от того, что вы используете.
После представления этой информации, вы можете передавать и использовать собственные аргументы. Мы не будем этим заниматься.
Нужно отметить, что большинство из этих аргументов не нужны; в конце концов, у вас уже есть доступ ко всем ссылкам? Тем не менее, данная возможность полезна в нескольких ситуациях:
- Когда появляется необходимость сократить имена аргументов, для экономии байтов памяти.
- Если вы используете RequireJS или другой модуль загрузки, вам нужно только, создать зависимость объекта от функции
Application
. Все остальное будет доступно благодаря аргументам, вызываемым функциейModule
.
Как бы там ни было, но давайте вернемся к объяснению остальных действий, выполняемых кодом выше. Внутри функции, вы можете использовать символы закрытия и создавать частные переменные и функции, что мы, собственно говоря, и сделали. Вы также можете представлять данные и функции открыто, добавляя их в качестве свойств myModule
. Это и есть процедура создания и расширения нашего модуля. Нет необходимости что-либо возвращать, потому что модуль будет доступен непосредственно через команду App
, обо всем этом я расскажу в теме “доступ к модулю” в разделе ниже.
Примечание: убедитесь, что вы всего лишь добавляете свойство к module
переменной и не устанавливаете ее значение равным чему-нибудь (например, myModule = {…}
). В случае, если вы все же присвоили какое-то значение module
переменной, то поменяется адресация, и позже в модуле появятся соответствующие изменения.
Ранее я отмечал, что можно использовать в качестве пользовательских аргументов. Фактически, вы можете использовать столько пользовательских аргументов, сколько захотите. Взгляните на код ниже, чтобы увидеть, как это сделать.
App.module("myModule", function(myModule, App, Backbone, Marionette, $, _, customArg1, customArg2){
// Create Your Module
}, customArg1, customArg2);
Как вы уже могли заметить, если вы передаете дополнительные аргументы в module
, то они будут переданы и в функцию, которая описывает данный модуль. Главное преимущество, которое я вижу от этого действия – это экономия нескольких байт памяти; кроме этого, никакой пользы я больше не вижу.
Еще один момент, который следовало бы отметить это то, что ключевое слово this
доступно в функции и на самом деле относится к модулю. Это означает, что не нужно обязательно использовать первый аргумент, но вы должны иметь ввиду, что потеряете преимущество экономии памяти. Давайте переделаем представленный выше код, используя ключевое слово this.
Вы увидите, что данный пример кода во многом похож на пример с myModule
.
App.module("myModule", function(){ // Private Data And Functions
var privateData = "this is private data";
var privateFunction = function(){
console.log(privateData);}
// Public Data And Functions
this.someData = "public data";
this.someFunction = function(){
privateFunction();
console.log(this.someData);}
});
Если вы заметили, я не использую какие-либо из аргументов, на этот раз я решил не перечислять их. Вы также должны понимать, что можно пропустить первый аргумент и использовать только ключевое слово this
.
Разбиение процесса инициализации.
Последнее, что мне хотелось бы упомянуть о процессе инициализации – это возможность ее разбиения. Я не знаю точно, для чего это может вам понадобиться, но, возможно, кто-то захочет в дальнейшем расширить модуль, так что разбиение инициализации может помочь им избавится от зависимости перед исходным кодом. Вот пример разбиения процесса инициализации:
// File 1
App.module("myModule", function(){
this.someData = "public data";});
// File 2
App.module("myModule", function(){ // Private Data And Functions
var privateData = "this is private data";
var privateFunction = function(){
console.log(privateData);}
this.someFunction = function(){
privateFunction();
console.log(this.someData);}
});
Этот код дает тот же результат, что и предыдущая инициализация, с тем лишь отличием, что она распределена. Это работает, потому что в File 2
происходит вызов модуля, который мы инициализировали в File 1
(при условии, что File 1
был запущен до File 2
). Если вы пытаетесь получить доступ к частной переменной или функции, она должна быть определена в модуле инициализации, там, где она используется, потому что доступ возможен только в рамках структурного блока.
Вызов модуля.
Что хорошего в создании модулей, если мы не можем получить к ним доступ? Для полноценного использования модуля необходимо правильно организовать функцию его вызова. В самом первом примере фрагментов кода, вы видели, что когда я вызывал функцию module
, я присвоил ее возвращение значения переменной. Это потому, что мы используем один и тот же метод и инициализации и вызова модулей.
var myModule = App.module("myModule");
Обычно, если вы просто пытаетесь вызвать модуль, то обращаетесь к первому аргументу, а функция module
прекращает свое выполнение. Но если вы переходите к функции обращаясь ко второму аргументу, то модуль будет расширен с новой функциональностью и все равно будет вызываться с вновь созданными или измененными модулями. Это означает, что вы можете инициализировать свой модуль и получить к нему доступ с помощью одного метода вызова.
Однако, это не единственный способ вызова модулей. Когда модуль будет создан, он получит привязку непосредственно к Application
объекту, для которого был создан. Это означает, что вы можете также использовать нормальное обозначение точки доступа к модулю; но на этот раз, обозначение должно быть определено заранее, иначе вы получите неопределенность
.
// Works but I don't recommend it
var myModule = App.myModule;
Хотя представленный синтаксис короче, но он не передает нужный смысл для других разработчиков. Я бы рекомендовал использовать функцию module
для получения доступа к нужным модулям. Прежде всего потому, что о …
Если вы хотите прочитать полностью статью, посетите сайт наших спонсоров