JavaScript модули
Что такое модуль
Для начала ответим на вопрос что такое JavaScript модули и зачем они нужны. Для этого, немного погрузимся в темные времена, когда разработка сайтов обладающих какой-то не сложной динамической функциональностью на стороне клиента, являлась сложной задачей, и начнем с того, что рассмотрим предпосылки возникновения модулей.
До возникновения модулей и стандарта ES6 в JavaScript видимость переменных ограничивалась только функциями. Если переменная была объявлена вне функции, она глобальная и доступна в любом месте на странице и в любом подключаемом файле со скриптами. В больших сайтах или приложениях это порождало большие неудобства и проблемы, так как в разных файлах имена переменных могли совпадать, что приводило к возникновению ошибок. Эта проблема решалась с помощью так называемых немедленно вызываемых функций — Immediately Invoked Function Expression (IIFE).
Все содержимое js-файла помещалось в такую конструкцию:
(function() {
//все содержимое JavaScript файла
})();
Все внутри этой функции немедленно выполняется, то есть то же самое, что без нее, но при этом все переменные объявлены внутри этой функции и их область видимости ограничена ею. Таким образом Front-End разработчики могли заниматься разными частями приложения и не мешать друг другу.
Следует упомянуть, что внутри команды, программисты вполне могли договорится об использовании определенных пространств имен, но они также могли использовать и сторонние скрипты, поэтому использование IIFE был единственным рабочим вариантом для структурирования JavaScript приложения, но при этом возникали трудности с передачей данных в и из этого псевдо модуля. То есть, JavaScript разработчики нуждались в лучшем инструменте, который был принесен стандартом ES6 в 2015.
JavaScript модуль это механизм структурирования и группирования кода, который позволяет инкапсулировать код в один файл и определять какие его части будут видны окружающей среде. Для этого используются два ключевых слова Import
и Export
. Export
позволяет создавать модуль и экспортировать определенный функционал, Import
, соответственно, позволяет этот функционал использовать вне модуля.
Характеристики модулей
Модуль это синглтон (singleton), он единственный в своем роде, то есть если мы подключаем один и тот же модуль, мы будем использовать не копии этого модуля, а одни и те же данные. То есть, если в каком-то месте, что-то поменяется в нем, эти изменения будут во всех импортах.
Я это уже упоминал, но стоит акцентировать на этом, один модуль — это один файл, нельзя разместить несколько модулей в одном файле.
Создание модулей
Создание JavaScript модуля, как я отмечал ранее, предполагает использование ключевого слова Export
. Оно позволяет веб разработчику раскрывать вне модуля порции функционала. Это делается тремя разными способами: именной экспорт и экспорт по умолчанию.
Именной экспорт
Именной экспорт позволяет открывать доступ к чему-то у чего есть имя. Это может быть, например, функция или просто переменная. Зная это имя мы можем потом его использовать для импорта в другом месте.
Базовый код для именного экспорта в файле модуля someFunctions.js
:
export function firstFunction() {
//какой-то js код
}
export function secondFunction() {
//какой-то js код второй функции
}
В примере выше не обязательно каждый раз писать export
перед тем, что хотим экспортировать, особенно если в модуле много элементов для экспорта. Можно все экспортировать одним махом:
export {firstFunction, secondFunction};
В этом случае можно также переименовать что-то для экспорта, например, вот так:
export {firstFunction, secondFunction as newFunction};
Затем мы можем импортировать и использовать эти функции в другом JavaScript файле следующим образом:
import {firstFunction, secondFunction} from './someFunctions.js';
Или в случае переименования:
import {firstFunction, newFunction} from './someFunctions.js';
Тут особенным является то, что нужно знать имена элементов, которые экспортируются/импортируются.
Экспорт по умолчанию
Этот способ позволяет не привязываться к определенным именам, экспортировать и потом импортировать функционал при этом не зная, как он называется в исходном модуле.
Чтобы создать экспорт по умолчанию нужно использовать ключевое слово default
. Например:
export default function firstFunction() {
//какой-то js код
}
Другой вариант экспорта по умолчанию:
export {firstFunction as default};
В таком случае для импорта, не обязательно знать имя этой функции, и можно использовать любое другое имя, которое может не совпадать с оригинальным:
import anyFunction from './someFunctions.js';
Обратите внимание, при использовании именного импорта, не используются фигурные скобки. Также следует отметить, что экспортировать по умолчанию можно только одну сущность на один модуль, но при этом можно комбинировать его с именной экспорт. То есть, ключевое слово default
можно использовать только один раз, но одновременно можно экспортировать и другие вещи использую именной экспорт:
export {firstFunction as default, secondFunction};
Использование модулей
Модули из стандарта ES6 поддерживаются всеми современными браузерами, даже Edge. Internet Explorer, конечно же не поддерживает их, но на момент написания статьи ему осталось жить приблизительно пол года и Microsoft официально перестанет его поддерживать. Так, что, если вы веб разработчик, можете смело использовать модули в своей работе.
Чтобы включить и использовать файл-модуль в HTML страницу нужно в теге скрипт добавить атрибут type="module"
:
<script src="js/app.js" type="module"></script>
Этот атрибут включить возможность использования export/import
функциональности в данном файле.
Файл app.js
можно использовать чтобы объединить все модули и всю функциональность. Рассмотрим все варианты импортов.
Именной импорт
import {firstFunction, secondFunction} from './someFunctions.js';
В данном случае нужно знать имена экспортируемых сущностей, чтобы иметь возможность их импортировать.
Импорт по умолчанию
import anyFunction from './someFunctions.js';
При импорте по умолчанию не обязательно знать имя того, что экспортируется. Если нужно импортировать еще что-то, нужно использовать именной импорт или комбинировать в гибридный следующим образом:
import anyFunction, {secondFunction} from './someFunctions.js';
Еще одним вариантом импорта будет импорт всего:
import * as func from './someFunctions.js';
И использовать импортируемые функции как методы объекта func
: func.firstFunction()
.
На этом все. Как видите, все очень просто и прямолинейно, но эта простота вносит порядок в организации понятной структуры JavaScript проекта, что облегчает работу фронт-энд веб разработчиков в команде, а значит ускоряет и удешевляет создание сайтов и веб приложений.