Модульное программирование - очень распространенный паттерн программирования JavaScript. Как правило, это может облегчить понимание кода, но есть много отличных практик, которые не очень хорошо известны.
База
Давайте впервые кратко рассмотрим некоторые модульные закономерности, поскольку Эрик Мираглия (разработчик Yui) впервые опубликовал блог три года назад, описывающий модульные узоры. Если вы уже очень хорошо знакомы с этими модульными режимами, вы можете напрямую пропустить этот раздел и начать читать из «Advanced Mode».
Анонимное закрытие
Это основная структура, которая делает все возможным, и это также лучшая особенность JavaScript. Мы просто создадим анонимную функцию и немедленно выполним ее. Весь код будет выполняться в рамках этой функции и жить в закрытии, обеспечивающем приватизацию, которая достаточно, чтобы позволить переменным в этих закрытиях проходить через весь срок службы нашего приложения.
Кода -копия выглядит следующим образом:
(function () {
// ... все VAR и функции только в этой области
// все еще поддерживает доступ ко всем глобальным
} ());
Обратите внимание на самые внешние кронштейны этой пары обертывания анонимных функций. Из -за языковых характеристик JavaScript это необходимо для скобок. Заявления, начиная с функции ключевого слова в JS, всегда считаются декларативными функциями. Оберните этот код в скобки, чтобы интерпретатор знал, что это выражение функции.
Глобальный переменный импорт
JavaScript имеет функцию, называемую неявными глобальными переменными. Независимо от того, где используется имя переменной, интерпретатор найдет оператор объявления VAR переменной в обратном направлении в соответствии с цепочкой области. Если оператор объявления VAR не найден, тогда эта переменная будет считаться глобальной переменной. Если эта переменная используется в операторе назначения, а переменная не существует, будет создана глобальная переменная. Это означает, что его легко использовать или создавать глобальные переменные в анонимных закрытиях. К сожалению, это делает код, написанным чрезвычайно трудным для поддержания, потому что для интуитивных чувств людей невозможно сразу сказать, что эти переменные являются глобальными.
К счастью, наши анонимные функции обеспечивают простые обходные пути. Просто передайте глобальную переменную в качестве параметра в нашу анонимную функцию, вы можете получить более четкий и более быстрый код, чем неявная глобальная переменная. Вот пример:
Кода -копия выглядит следующим образом:
(function ($, yahoo) {
// теперь есть доступ к глобальным jQuery (как $) и Yahoo в этом коде.
} (jQuery, Yahoo));
Экспорт модуля
Иногда вы хотите не только использовать глобальные переменные, вы также хотите объявить их для повторного использования. Мы можем сделать это легко, производя их - через возвращаемое значение анонимных функций. Это завершит базовую модульную модель, а следующее будет полным примером:
Кода -копия выглядит следующим образом:
var module = (function () {
var my = {},
privateVariable = 1;
function privatemethod () {
// ...
}
my.moduleproperty = 1;
my.modulemethod = function () {
// ...
};
вернуть мой;
} ());
Обратите внимание, что мы объявили глобальный модуль, называемый модуль, который имеет 2 публичных свойства: метод, называемый module.modulemethod, и переменная, называемая модуль. Модулепроперти. Кроме того, он поддерживает частное встроенное состояние, которое использует закрытие анонимных функций. В то же время мы можем легко импортировать требуемые глобальные переменные и использовать этот модульный паттерн, как мы узнали ранее.
Расширенный режим
Основа, описанной в вышеуказанном разделе, достаточно, чтобы справиться со многими ситуациями, и теперь мы можем дополнительно разработать эту модульную модель для создания более мощных и масштабируемых структур. Давайте начнем с модуля модуля и представим эти продвинутые режимы один за другим.
Режим масштабирования
Весь модуль должен быть ограничением модульного режима в одном файле. Любой, кто участвует в крупном проекте, поймет ценность разделения нескольких файлов с JS. К счастью, у нас есть отличная реализация для усиления модулей. Во -первых, мы импортируем модуль, добавляем к нему свойства и, наконец, экспортируют его. Вот пример - увеличить исходный модуль:
Кода -копия выглядит следующим образом:
var module = (function (my) {
my.anothermethod = function () {
// Добавлен метод ...
};
вернуть мой;
} (Модуль));
Мы используем ключевое слово var для обеспечения согласованности, хотя здесь нет необходимости. После того, как этот код будет выполнен, наш модуль уже имеет новый публичный метод с именем Module.AnotherMethod. Этот увеличенный файл также будет поддерживать свое собственное встроенное состояние и импортные объекты.
Режим широкого масштабирования
Наш пример выше требует, чтобы наш модуль инициализации выполнялся сначала, а затем амплифицированный модуль был выполнен, и, конечно, иногда это не обязательно может потребоваться. Одна из лучших вещей JavaScript может сделать для повышения производительности, - это асинхронно выполнять сценарии. Мы можем создавать гибкие многопотатические модули и позволить их загружать в любом порядке через широкий режим зум. Каждый файл должен быть организован в следующей структуре:
Кода -копия выглядит следующим образом:
var module = (function (my) {
// Добавить возможности ...
вернуть мой;
} (Модуль || {}));
В этом шаблоне выражение var делает его необходимым. Обратите внимание, что если модуль не был инициализирован, этот оператор импорта создаст модуль. Это означает, что вы можете использовать такой инструмент, как LABJ, для загрузки всех файлов ваших модулей параллельно, не будучи блокированным.
Режим плотного увеличения
Режим широкополосного режима очень хороший, но он также нанесет некоторые ограничения на ваш модуль. Самое главное, вы не можете безопасно перезаписать свойства модуля. Вы не можете использовать свойства из других файлов при инициализации (но вы можете использовать их при запуске). Режим плотного увеличения содержит загруженную последовательность и позволяет переопределять свойства. Вот простой пример (Zoom в нашем оригинальном модуле):
Кода -копия выглядит следующим образом:
var module = (function (my) {
var old_modulemethod = my.modulemethod;
my.modulemethod = function () {
// переопределение метода, имеет доступ к Old через Old_modulemethod ...
};
вернуть мой;
} (Модуль));
Мы переопределяем реализацию module.modulemethod в примере выше, но при необходимости мы можем поддерживать ссылку на исходный метод.
Клон и наследство
Кода -копия выглядит следующим образом:
var module_two = (function (old) {
var my = {},
ключ;
для (ключ в старом) {
if (old.hasownproperty (key)) {
my [key] = old [key];
}
}
var super_modulemethod = old.modulemethod;
my.modulemethod = function () {
// метод переопределения на клоне, доступ к Super через Super_Modulemethod
};
вернуть мой;
} (Модуль));
Эта модель, вероятно, является самым негибким вариантом. Это делает код аккуратным, но это происходит за счет гибкости. Как я писал выше, если свойство является объектом или функцией, оно не будет скопировано, но станет второй ссылкой на объект или функцию. Если вы измените один из них, вы одновременно измените другого (примечание переводчика: потому что они просто один!). Это может быть решено путем рекурсивного процесса клонирования, но клонирование функций не может быть решено, возможно, его можно решить с помощью Eval. Поэтому я рассказываю этот метод в этой статье только учитывать целостность статьи.
Крестные частные переменные
Существует значительное ограничение на разделение модуля на несколько файлов: каждый файл поддерживает собственные частные переменные и не может получить доступ к частным переменным для других файлов. Но эта проблема может быть решена. Вот пример широкоэтапного модуля, который поддерживает личные переменные в разных файлах:
Кода -копия выглядит следующим образом:
var module = (function (my) {
var _private = my._private = my._private || {},
_seal = my._seal = my._seal || function () {
Удалить my._private;
Удалить my._seal;
Удалить my._unseal;
},
_unseal = my._unseal = my._unseal || function () {
my._private = _private;
my._seal = _seal;
my._unseal = _unseal;
};
// Постоянный доступ к _private, _seal и _unseal
вернуть мой;
} (Модуль || {}));
Все файлы могут устанавливать свойства на соответствующие _private переменные, и они понимают, что к ним можно получить доступ к другим файлам. Как только этот модуль загружен, приложение может вызовать модуль. Если этот модуль должен быть переоборудован, внутренний метод в любом файле может вызвать _unseal () перед загрузкой нового файла, и снова вызовет _seal () после выполнения нового файла. Сейчас я использую этот шаблон на работе, и я больше нигде не видел его. Я думаю, что это очень полезная модель, и стоит написать статью об этой модели.
Подмодули
Наш последний продвинутый режим, очевидно, самый простой. Есть много отличных примеров создания подмодулей. Это похоже на создание обычного модуля:
Кода -копия выглядит следующим образом:
Module.sub = (function () {
var my = {};
// ...
вернуть мой;
} ());
Хотя это кажется простым, я думаю, что здесь стоит упомянуть. Подмодули имеют все расширенные преимущества общих модулей, включая режим усиления и состояние приватизации.
в заключение
Большинство передовых режимов могут быть объединены, чтобы создать более полезный режим. Если я действительно хочу порекомендовать модульный шаблон для разработки сложных приложений, я бы решил объединить режим широкого усиления, частные переменные и подмодули.
Я не рассматривал производительность этих режимов, но я бы предпочел превратить это в более простой способ мышления: если модульный режим обладает хорошей производительности, он может сделать отличную работу, чтобы минимизировать его, ускоряя загрузку этого файла скрипта. Использование режима широкого увеличения позволяет простые неблокирующие параллельные загрузки, которые ускоряют загрузки. Время инициализации может быть немного медленнее, чем другие методы, но оно того стоит после взвешивания плюсов и минусов. Пока импорт глобальной переменной является точным, следует затронуть производительность времени выполнения, а также возможно достичь более быстрой скорости бега в подмодулях, сокращая контрольную цепь с частными переменными.
В заключение, вот пример детского модуля, динамически загружающего себя в свой родительский модуль (создавая его, если родительский модуль не существует). Для простоты я удалил личные переменные, и, конечно, очень просто добавить частные переменные. Этот шаблон программирования позволяет загружать базу кода иерархической структуры параллельно через подмодули.
Кода -копия выглядит следующим образом:
var util = (function (parent, $) {
var my = parent.ajax = parent.ajax || {};
my.get = function (url, params, обратный вызов) {
// хорошо, так что я немного обманываю :)
return $ .getjson (url, params, обратный вызов);
};
// и т. д...
вернуть родитель;
} (Util || {}, jQuery));
В этой статье суммируются текущие лучшие практики «модульного программирования JavaScript» и объясняет, как его применить на практике. Хотя это не основной учебник, вы можете понять его лишь небольшим пониманием основного синтаксиса JavaScript.