Модули в JavaScript (ES6) реализованы на основе файлов, и находятся они с файлами в отношении "один-к-одному". Попросту говоря, какой-либо конкретный файл, содержащий js-код, можно смело считать отдельным модулем. При этом, как следует из вышенаписанного, один файл представляет лишь один модуль, в нём не может быть (по крайней мере, на текущий момент) организовано размещение одновременно нескольких модулей.
Любой ваш проект (программа, задача, приложение) - это код. И этого кода может быть очень много. Но даже в небольших по объёму проектах без должной структуризации кода весьма легко запутаться в используемых константах и переменных (далее - переменные), функциях и классах и допустить ошибки. Так вот, базовым и наиболее естественным средством структуризации вашего кода служит его разбиение на отдельные модули. И это помогает решить ряд задач и проблем:
export
и/или default export
). Таким образом снижается вероятность непреднамеренного или злонамеренного изменения кода одной части программы из другой части, повышается уровень безопасности.
Далее будут подробно рассмотрены синтаксис модулей, способы и примеры экспортирования и импортирования.
Почти все последующие уроки этого курса, а также все остальные курсы на Хекслете активно используют модули. Такой подход максимально приближает нас к реальной жизни, когда проекты состоят из сотен, а то и тысяч файлов и библиотек, которые активно пользуются друг другом.
При работе с модулями будет полезным сразу наработать некоторые модели поведения, позволяющие вам с легкостью определять, какой код вам доступен на исполнение, откуда пришел этот код и как его увидеть. Фидбек, который мы получаем от наших пользователей, говорит о том, что, как раз, в этом моменте больше всего затыков.
Ниже описан основной алгоритм, по которому нужно анализировать файл с кодом, над которым вы сейчас работаете. Этот алгоритм не является специфичным для работы в среде Хекслета, так нужно делать в принципе:
Math
).from './...
, то есть содержит
./
, значит импортируется модуль, содержимое которого находится в текущей файловой системе. Это автоматически
означает несколько вещей. Первое, вы всегда можете открыть этот файл и посмотреть, что там написано, второе,
вы не сможете импортировать этот модуль в другой среде, что очевидно, ведь этого файла там нет.from 'name'
содержит только имя, без лидирующего ./
, это означает, что модуль подгружается либо из
стандартной библиотеки nodejs
, либо из установленных пакетов. Визуально невозможно отличить одно от другого.
В данном случае необходимо проявить смекалку и попробовать загуглить имя таким способом nodejs name
.
Если в выдаче будет ссылка на официальную документацию, то значит это модуль ноды, если на репозиторий npm
,
значит это обычный пакет, который почти наверняка лежит на гитхабе, что можно проверить таким запросом
github js name
, где name
это имя пакета.Если из модуля экспортировано множество функций, то, как мы уже знаем, импортировать их можно с помощью такой строчки:
import * as name from './name';
// name.someFunction();
Иногда бывает удобнее импортировать функции в текущий модуль напрямую, без необходимости указывать исходный модуль, и достичь этого можно таким образом:
import { someFunction, anotherFunction } from './name';
// someFunction();
Часто встречаются ситуации, в которых нужно импортировать функции из нескольких разных модулей, но имена этих функций совпадают. Как мы помним из теории, это одна из ключевых целей модулей, предотвратить коллизии имен. Так вот, пока функции живут внутри своих модулей, эта коллизия разруливается автоматически, но при необходимости использовать эти функции в третьем модуле, нужен дополнительный механизм. Выражается он в том, что при импорте мы можем локально переименовать любую функцию, другими словами ей можно задать алиас.
import { request as r, get } from 'http';
r();
По умолчанию также можно экспортировать любую константу, что открывает такую возможность:
const func = () => {}
export default func;
При этом снаружи это имя никак не используется, любой экспорт по умолчанию импортируется под любым именем.
Синтаксис экспорта по умолчанию таков, что после обязательных ключевых слов export default
можно указать выражение, будь то константа:
const favColour = 'red';
export default favColour;
или анонимная функция:
export default () => 'Hello, world!';
/*
вариант для функции типа 'Function Expression'
export default function() {
return 'Hello, world!';
}
*/
или даже просто литерал, например:
export default 'Hello, world!';
В отличие от именованного экспорта здесь после ключевых слов недопустимо указывать объявления переменных (с использованием const, let, var) и возможен только один дефолтный экспорт на модуль.
donor.js
- файл, в котором размещены экспортные функции.
acceptor.js
- файл, в котором происходит импорт функций.
Давайте наполним donor.js экспортными константами и функциями. Для полноты картины к именованному экспорту мы добавили ещё и экспорт по умолчанию (это допустимо, хотя и не принято так делать, по смыслу экспорта по умолчанию он должен быть единственным экспортом на модуль):
// donor.js
export const getFirstWeekday = () => 'Monday';
export const getSecondWeekday = () => 'Tuesday';
/* экспортируем функцию типа 'Function Declaration' */
export function getThirdWeekday () {
return 'Wednesday';
}
export const fourthWeekday = 'Thursday';
const getFifthWeekday = () => 'Friday';
export default getFifthWeekday; // export default () => 'Friday'
/* две функции ниже не будут экспортированы */
const firstWeekendDay = 'Saturday';
const getLastWeekendDay = () => 'Sunday';
/*
аналогичный альтернативный вариант экспорта заключается в том, что не надо помечать функции и
переменныe ключевым словом 'export' ('default export'), вместо этого достаточно написать
следующее выражение (сформировать объект для экспорта):
export { getFirstWeekday, getSecondWeekday, getThirdWeekday, fourthWeekday, getFifthWeekday as default };
*/
Теперь рассмотрим несколько вариантов, как можно импортировать эти переменные и функции (далее для краткости - функции) в модуль acceptor.js:
---> Импортируем все функции из donor.js в виде объекта, которому необходимо дать произвольный (соответствующий общим правилам именования переменных) псевдоним. Обращаемся к импортированным функциям как к свойствам этого объекта:
// acceptor.js
import * as someName from './donor'; // имя модуля можно указывать без расширения
// посмотрим, что из себя представляет импортированный объект someName
console.log(someName);
/*
{ getThirdWeekday: [Function: getThirdWeekday],
getFirstWeekday: [Function: getFirstWeekday],
getSecondWeekday: [Function: getSecondWeekday],
fourthWeekday: 'Thursday',
default: [Function: getFifthWeekday]
}
*/
someName.getFirstWeekday(); // 'Monday'
someName.getThirdWeekday(); // 'Wednesday'
someName.fourthWeekday; // 'Thursday'
someName.default(); // доступ (при данном виде импорта) к значению по умолчанию: 'Friday'
someName.firstWeekendDay; // undefined, такого свойства не существует, потому что переменная не была экспортирована
---> Сделаем выборочный импорт функций из donor.js. Для этого перечислим в фигурных скобках имена интересующих нас функций. Обращаемся к импортированным функциям по этим именам. При этом им можно давать псевдонимы, далее в текущем модуле доступ к таким функциям будет происходить только по псевдониму (это может пригодится в том случае, если в модуле уже существует функция с таким именем, для разрешения конфликта имён):
// acceptor.js
import { getFirstWeekday, getThirdWeekday, fourthWeekday as fourthDay } from './donor';
// константа с именем 'fourthWeekday' уже существует в модуле
const fourthWeekday = 'This is Thursday';
getFirstWeekday(); // 'Monday'
getThirdWeekday(); // 'Wednesday'
fourthDay; // 'Thursday'
fourthWeekday; // 'This is Thursday'
---> Импортируем из модуля donor.js значение по умолчанию. Для этого достаточно просто указать после ключевого слова import
произвольное (наиболее подходящее и удобное) имя. В таком случае по этому имени можно будет обращаться к значению по умолчанию из импортируемого модуля:
// acceptor.js
import nameOfDefault from './donor';
// как вы помните, значением по умолчанию модуля donor.js является функция, возвращающая строку 'Friday'
nameOfDefault(); // 'Friday'
Также есть возможность импортировать одновременно и значение по умолчанию и другие экспортированные компоненты. Это можно сделать несколькими способами, приведём примеры:
// acceptor.js
// важно: имя значения по умолчанию стоит первым и не заключено в фигурные скобки
import nameOfDefault, { getFirstWeekday, getSecondWeekday } from './donor';
// как вы помните, значением по умолчанию модуля donor.js является функция, возвращающая строку 'Friday'
nameOfDefault(); // 'Friday'
getFirstWeekday(); // 'Monday'
getSecondWeekday(); // 'Tuesday'
тот же самый результат можно получить ещё одним альтернативным способом:
// acceptor.js
import { default as nameOfDefault, getFirstWeekday, getSecondWeekday } from './donor';
// как вы помните, значением по умолчанию модуля donor.js является функция, возвращающая строку 'Friday'
nameOfDefault(); // 'Friday'
getFirstWeekday(); // 'Monday'
getSecondWeekday(); // 'Tuesday'
Вам ответят команда поддержки Хекслета или другие студенты.
Выделите текст, нажмите ctrl + enter и отправьте его нам. В течение нескольких дней мы исправим ошибку или улучшим формулировку.
Загляните в раздел «Обсуждение»:
Статья «Ловушки обучения»
Вебинар «Как самостоятельно учиться»
Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно.
Наши выпускники работают в компаниях:
Зарегистрируйтесь или войдите в свой аккаунт