От автора: одна из главных особенностей ES6 — поддержка JavaScript встроенных модулей. Модули позволяют совместно использовать код различными файлами, используя синтаксис export и import. Это значительное улучшение по сравнению с использованием тегов script и глобальных переменных для совместного использования кода.
Использование тегов script было сопряжено с ошибкам, так как порядок загрузки имеет значение. Указание script в неправильном порядке может привести к тому, что программа выполнит код, который еще не был объявлен. Это также заставляло нас писать спагетти-код без реальной структуры или логической композиции. Эта проблема устраняется при использовании модулей, потому что все экспортируется и импортируется непосредственно между файлами. Кроме того, мы можем легко определить определение импортируемого кода, поскольку оно явно указывает, в какие модули код импортируется и на какие ссылается.
Экспорт и импорт
Чтобы сделать код в файле JavaScript импортируемым, мы должны явно экспортировать его с помощью оператора export. Для этого мы просто помещаем export перед переменной или константой, которую вы хотите предоставить другим файлам. Например, мы можем написать:
export let num = 1;
Это экспортирует переменную num, чтобы другие модули могли использовать ее через import. Мы можем экспортировать все, что объявляется с помощью var, let, const, а также функции и классы. Экспортируемые элементы должны быть объявлены на верхнем уровне. export не может использоваться где-либо еще, кроме как внутри функций и классов.
Мы можем экспортировать несколько членов одновременно. Все, что нам нужно сделать, это заключить все члены в фигурные скобки, разделенные запятыми. Например, мы можем написать:
const num1 = 1; const num2 = 2; const num3 = 3; export {num1, num2, num3};
Это позволит нам импортировать num1, num2 и num3 в других файлах JavaScript. Теперь, когда мы экспортировали элементы, мы можем импортировать их в другие файлы JavaScript. Мы можем использовать оператор import для импорта одного или нескольких членов в модуль и работы с ними. Например, если в moduleA.js у нас есть следующее:
const num1 = 1; const num2 = 2; const num3 = 3; export {num1, num2, num3};
Тогда в moduleB.js мы можем написать следующий код для импорта элементов moduleA.js:
import {num1, num2, num3} from './moduleA'
Путь после ключевого слова from начинается с точки. Точка означает, что мы в текущей папке. Это предполагает, что moduleA.js и moduleB.js находятся в одной папке. Если они находятся в другой папке, то у нас есть указание пути moduleA.js относительно moduleB.js, если мы хотим импортировать экспортированные элементы moduleA.js в moduleB.js. Например, если moduleA.js на один уровень выше moduleB.js, то в moduleB.js мы пишем:
import {num1, num2, num3} from '../moduleAFolder/moduleA'
2 точки до пути означают, что мы поднимаемся на один уровень вверх по дереву каталогов, а затем получаем moduleAFolder и затем получаем moduleA.js.
Мы также можем использовать модули JavaScript в тегах script. Чтобы сделать это, нам нужно установить для атрибута type тега script значение module. Например, если мы хотим использовать moduleA.js в HTML-файле, мы можем написать:
<script type='module' src='moduleA.js'></script>
Мы можем использовать import и exportв модулях JavaScript. Они не будут работать с обычными скриптами.
Скрипты запускаются в строгом режиме автоматически, поэтому мы не можем случайно объявлять глобальные переменные и делать другие вещи, которые могут быть выполнены без включения строгого режима. Они также автоматически загружаются асинхронно, поэтому нам не придется беспокоиться о длинных скриптах, блокирующих страницу. Кроме того, import и export происходит только между двумя скриптами, так что никакие глобальные переменные не устанавливаются. Поэтому их нельзя просматривать в консоли напрямую.
Экспорт по умолчанию
Также есть вариант экспорта по умолчанию для экспорта членов модуля. Ранее мы экспортировали переменную таким образом, чтобы импортировать их по имени. Существует также экспорт по умолчанию, который экспортирует один элемент из модуля без необходимости ссылаться на него при импорте явно по имени. Например, если у нас есть один элемент в модуле, который мы хотим экспортировать, мы можем написать следующее в moduleA.js:
const num = 1; export default num;
Когда вы используете export default, фигурные скобки не указываются. Затем в файле, куда вы хотите импортировать члена, в moduleB.js мы пишем:
import num from './moduleA'
Еще раз, мы опускаем фигурные скобки. Это связано с тем, что для каждого модуля разрешен только один экспорт по умолчанию. В качестве альтернативы, мы можем написать в moduleB.js следующее:
import {default as num} from './moduleA'
Переименование импорта и экспорта
Если у нас много модулей и их экспортируемые члены имеют одинаковые имена, если мы попытаемся импортировать несколько модулей, возникнут конфликты. Это будет проблема, которую нам нужно решить. К счастью, в JavaScript есть ключевое слово as, которое позволяет переименовывать экспорт и импорт, чтобы избежать конфликтов имен в коде. Чтобы использовать ключевое слово as для переименования экспорта, мы пишем в moduleA.js следующее:
export { num1 as numOne, num2 as numTwo }
Затем в moduleB.js мы можем импортировать их, написав:
import { numOne, numTwo } from './moduleA'
Альтернативно, мы можем выполнить переименование при импорте. Для этого в moduleA.js мы добавим:
export { num1, num2 }
Затем в moduleB.js мы помещаем:
import { num1 as numOne, num2 as numTwo } from './moduleA'
Если мы попытаемся импортировать элементы из модулей, в которых элементы имеют одинаковое имя, например:
import { num1, num2 } from './moduleA'; import { num1, num2 } from './moduleB'; import { num1, num2 } from './moduleC';
мы получим SyntaxError. Поэтому мы должны переименовать их, чтобы модуль запускался:
import { num1 as num1A, num2 as num2A } from './moduleA'; import { num1 as num1B, num2 as num2B } from './moduleB'; import { num1 as num1C, num2 as num2C } from './moduleC';
Более простой способ импортировать из нескольких модулей, содержащих элементы с одинаковыми именами — импортировать все экспортированные элементы модуля как один объект. Мы можем сделать это с помощью звездочки. Например, вместо:
import { num1 as num1A, num2 as num2A } from './moduleA'; import { num1 as num1B, num2 as num2B } from './moduleB'; import { num1 as num1C, num2 as num2C } from './moduleC';
мы можем написать:
import * as moduleA from './moduleA'; import * as moduleB from './moduleB'; import * as moduleC from './moduleC';
Тогда в коде ниже в импортах мы можем написать:
moduleA.num1; moduleA.num2; moduleB.num1; moduleB.num2; moduleC.num1; moduleC.num2;
Мы также можем экспортировать и импортировать классы. Так что если у нас есть файл, который содержит один или несколько классов, например, файл Person.js с классом:
class Person { constructor(firstName, lastName) { this._firstName = firstName; this._lastName = lastName; } get fullName() { return `${this.firstName} ${this.lastName}` } get firstName() { return this._firstName } get lastName() { return this._lastName } sayHi() { return `Hi, ${this.firstName} ${this.lastName}` } set firstName(firstName) { this._firstName = firstName; } set lastName(lastName) { this._lastName = lastName; } }
Затем мы пишем следующее для экспорта класса:
export { Person };
Это экспортирует класс Person, а затем, чтобы импортировать его, мы пишем:
import { Person } from './person';
Динамическая загрузка модулей
Модули JavaScript могут загружаться динамически. Это позволяет загружать модули только тогда, когда они нужны, а не все вместе при запуске приложения. Для этого мы используем функцию import(), которая возвращает промис. Когда модуль в аргументе загружен, то промис выполняется. Промис преобразуется в объект модуля, который затем может использоваться кодом приложения. Если у нас в Person.js есть класс Person, то мы можем динамически импортировать его с помощью следующего кода:
import('./Person') .then((module)=>{ const Person = module.Person; const person = new Person('Jane', 'Smith'); person.sayHi(); })
Или используя синтаксис async и await, мы можем поместить это в функцию:
const importPerson = async ()=>{ const module = await import('./Person'); const Person = module.Person; const person = new Person('Jane', 'Smith'); person.sayHi(); }importPerson();
Как видите, модули JavaScript очень полезны для организации кода. Это позволяет экспортировать то, что мы хотим представить в другие модули, устраняя необходимость в глобальных переменных. Кроме того, экспорт и импорт могут быть переименованы, чтобы избежать конфликта при импорте нескольких модулей. Также все экспортируемые элементы могут быть импортированы одновременно, так что мы получаем весь модуль как объект, а не импортируем отдельные элементы. Наконец, мы можем использовать, export default, если хотим экспортировать только одну вещь из модуля.
Автор: John Au-Yeung
Источник: https://levelup.gitconnected.com
Редакция: Команда webformyself.