Перевод статьи «JavaScript Modules», из сайта jsmodules.io
В новой версии JavaScript появится модульная система, главным образом вдохновленная идеей модулей Node.js.
В этой статье я расскажу, как это будет работать.
Создание модуля
В качестве упражнения, мы построим простой asap
модуль, который позволит назначать выполнение действий «как только так сразу» асинхронным образом. В Node.js, вы можете сделать это при помощи process.nextTick
, есть и разные подходы, которые работают во многих браузерах. Мы создадим модуль, который будет работать в любом окружении.1
Начнем с создания нового файла для нашего модуля. Назовём его asap.js. Модуль предоставляет единственную функцию, что называется экспорт по умолчанию(default export). Вы можете делать экспорт по умолчанию при помощи конструкции export default
.
var asap;
var isNode = typeof process !== "undefined" &.toString.call(process) === "[object process]";
if (isNode) {
asap = process.nextTick;
} else if (typeof setImmediate !== "undefined") {
asap = setImmediate;
} else {
asap = setTimeout;
}
export default asap;
Импорт модуля
Чтобы импортировать asap
из другого модуля, мы используем следующий синтаксис:
import asap from "asap";
asap(function() {
console.log("hello async world!");
});
Эта конструкция принимает дефолтную функцию экспортированную модулем asap
и хранит в переменной asap
, которую мы позже можем вызвать.
Именованный экспорт
Иногда модули должны экcпортировать несколько вещей, которые можно использовать по имени.
Например, в jQuery есть один главный экспорт (функция jQuery
) и несколько дополнительных именованных экспортов (ajax
, getJSON
, animate
и пр.). В модуле Node.js mkdirp
есть экспорт по умолчанию, который создает директорию и именованный экспорт под названием sync
, который делает то же, но синхронно.
В нашем случае, в дополнение к экспорту по умолчанию, asap
модуль может также предоставлять функцию later
, которая назначает выполнение кода на момент, когда другие сетевые или UI процессы уже произошли.
Наш модуль выглядит так же, кроме того, что мы добавили новое объявление экспорта.
var asap;
var isNode = typeof process !== "undefined" &.toString.call(process) === "[object process]";
if (isNode) {
asap = process.nextTick;
} else if (typeof setImmediate !== "undefined") {
asap = setImmediate;
} else {
asap = setTimeout;
}
export default asap;
export var later = isNode ? process.setImmediate : asap;
Именованный импорт
Теперь, когда мы экспортировали later
, мы можем импортировать его в другом модуле.
import { later } from "asap";
later(function() {
console.log("Running after other network events");
});
Для любопытных, вы можете импортировать экспорт по умолчанию и несколько именованных экспорта одной инструкцией импорта:
import asap, { later } from "asap";
И это все, что нужно сделать!
Удобства
Переименование именованного импорта
Иногда, импортируя именованный экспорт, вам нужно дать ему собственное локальное имя.
import { unlink as rm } from "fs";
rm(filename, function(err) { /* check errors */ });
Импорт в пространство имен
Может быть удобным, импортировать все именованные экспорты модуля в единственное локальное пространство имен.
import * as fs from "fs";
fs.unlink(filename, function(err) { /* check errors */ });
Сокращенный способ экспорта
Вы можете делать любое объявление в JavaScript (например var
или function
) именованным экспортом предваряя его ключевым словом export
.
// exports this function as "requestAnimationFrame"
export function requestAnimationFrame() {
// cross-browser requestAnimationFrame
}
// exports document.location as "location"
export var location = document.location;
Это также работает для новых объявлений, например class
или let
// exports this class as "File"
export class File() { /* implementation */ }
// exports "0.6.3" as "VERSION"
export let VERSION = "0.6.3";
Эти имена также доступны в локальной области видимости модуля, так что вы можете использовать их и в других функциях модуля.
Группирование экспорта
Вы можете экспортировать любое количество локальных переменных одной инструкцией.
function getJSON() {
// implementation
}
function postJSON() {
// implementation
}
function animate() {
// implementation
}
Групповое объявление экспорта можно поместить в любом месте файла, так вы можете размещать импорт и экспорт друг за другом, вверху модуля.
Особенности
JavaScript модули имеют несколько приятных особенностей, которые упрощают их использование и рефакторинг.
- JavaScript модули поддерживают отложенное связывание между модулями, как для именованного экспорта так и для экспорта по умолчанию. Оно просто работает.
- JavaScript модули разделяют имена существующие в экспорте по умолчанию (и цепочках прототипов) и другим именованным экспортом, предотвращая конфликты.
- С JavaScript модулями проще определить, что именно вы импортируете просто посмотрев на синтаксис. Это улучшает сообщения об ошибках, а также упрощает создание таких инструментов, как browserify или JSHint, которые должны работать надежно.
Примечания
1 Для реального использования данный модуль должен бы быть более детализированным, но для нашего примера этого достаточно.
Автор: jojo97