|
10 | 10 | Такие средства предлагались сообществом и ранее, например: |
11 | 11 |
|
12 | 12 | <ul> |
13 | | -<li>[CommonJS](http://wiki.commonjs.org/wiki/Modules/1.1)</li> |
14 | | -<li>[AMD](https://en.wikipedia.org/wiki/Asynchronous_module_definition)</li> |
15 | | -<li>[UMD](https://github.com/umdjs/umd)</li> |
| 13 | +<li>[AMD](https://en.wikipedia.org/wiki/Asynchronous_module_definition) -- одна из самых древних систем организации модулей, требует лишь наличия клиентской библиотеки, к примеру, [require.js](http://requirejs.org/), но поддерживается и серверными средствами.</li> |
| 14 | +<li>[CommonJS](http://wiki.commonjs.org/wiki/Modules/1.1) -- система модулей, встроенная в сервер Node.JS. Требует поддержки на клиентской и серверной стороне.</li> |
| 15 | +<li>[UMD](https://github.com/umdjs/umd) -- система модулей, которая предложена в качестве универсальной. UMD-модули будут работать и в системе AMD и в CommonJS.</li> |
16 | 16 | </ul> |
17 | 17 |
|
18 | | -Все они требуют различных библиотек или систем сборки для использования. |
| 18 | +Все перечисленные выше системы требуют различных библиотек или систем сборки для использования. |
19 | 19 |
|
20 | | -Новый стандарт отличается от них прежде всего тем, что это -- стандарт. А значит, со временем, будет поддерживаться браузерами без дополнительных утилит. |
21 | | - |
22 | | -Сейчас браузерной поддержки почти нет. Поэтому ES-модули используются вместе с системами сборки, такими как [webpack](http://webpack.github.io/), [brunch](http://brunch.io/) и другими, при подключённом [Babel.JS](https://babeljs.io). |
| 20 | +Новый стандарт отличается от них прежде всего тем, что это -- стандарт. А значит, со временем, будет поддерживаться браузерами без дополнительных утилит. |
23 | 21 |
|
| 22 | +Однако, сейчас браузерной поддержки почти нет. Поэтому ES-модули используются в сочетании с системами сборки, такими как [webpack](http://webpack.github.io/), [brunch](http://brunch.io/) и другими, при подключённом [Babel.JS](https://babeljs.io). Мы рассмотрим это далее. |
24 | 23 |
|
25 | 24 | ## Что такое модуль? |
26 | 25 |
|
|
30 | 29 |
|
31 | 30 | Другие модули могут подключать их через вызов `import`. |
32 | 31 |
|
33 | | -Нагляднее всего это проиллюстрировать примером. |
| 32 | +## export |
| 33 | + |
| 34 | +Ключевое слово `export` можно ставить: |
| 35 | + |
| 36 | +<ul> |
| 37 | +<li>перед объявлением переменных, функций и классов.</li> |
| 38 | +<li>отдельно, при этом в фигурных скобках указывается, что именно экспортируется.</li> |
| 39 | +</ul> |
34 | 40 |
|
35 | | -Модуль `one.js` экспортирует переменную `one`: |
| 41 | +Например: |
36 | 42 |
|
37 | 43 | ```js |
| 44 | +// экспорт прямо перед объявлением |
38 | 45 | export let one = 1; |
| 46 | + |
| 47 | +// можно и раздельно, в две строки вместо одной |
| 48 | +let two = 2; |
| 49 | +export {two}; |
39 | 50 | ``` |
40 | 51 |
|
41 | | -Модуль `two.js`: |
| 52 | +Заметим, что в фигурных скобках указывается не блок, не произвольное выражение, а только имя. |
| 53 | + |
| 54 | +Можно указать несколько: |
| 55 | +```js |
| 56 | +export {one, two}; |
42 | 57 | ``` |
43 | | -let two = 2; |
44 | 58 |
|
45 | | -export {two} |
| 59 | +Также можно указать, что переменная `one` будет доступна снаружи под именем `once`, а `two` -- под именем `twice`: |
| 60 | + |
| 61 | +```js |
| 62 | +export {one as once, two as twice}; |
| 63 | +``` |
| 64 | + |
| 65 | +Экспорт функций и классов выглядит так же: |
| 66 | +```js |
| 67 | +export class User { |
| 68 | + constructor(name) { |
| 69 | + this.name = name; |
| 70 | + } |
| 71 | +}; |
| 72 | + |
| 73 | +export function sayHi() { |
| 74 | + alert("Hello!"); |
| 75 | +}; |
| 76 | + |
| 77 | +// или export {User, sayHi} |
| 78 | +``` |
| 79 | + |
| 80 | +Заметим, что и у функции и у класса при таком экспорте должно быть имя. |
| 81 | + |
| 82 | +Так будет ошибка: |
| 83 | +```js |
| 84 | +// функция без имени |
| 85 | +export function() { alert("Error"); }; |
| 86 | +``` |
| 87 | + |
| 88 | +## import |
| 89 | + |
| 90 | +Другие модули могут подключать экспортированные значения при помощи ключевого слова `import`. |
| 91 | + |
| 92 | +Синтаксис: |
| 93 | + |
| 94 | +```js |
| 95 | +import {one, two} from "./nums"; |
| 96 | +``` |
| 97 | + |
| 98 | +Здесь: |
| 99 | +<ul> |
| 100 | +<li>`"./nums"` -- модуль, как правило это путь к файлу модуля.</li> |
| 101 | +<li>`one, two` -- импортируемые переменные, которые должны быть обозначены в `nums` словом `export`.</li> |
| 102 | +</ul> |
| 103 | + |
| 104 | +В результате импорта появятся локальные переменные `one`, `two`, которые будут содержать значения соответствующих экспортов. |
| 105 | + |
| 106 | +Например, при таком файле `nums.js`: |
| 107 | + |
| 108 | +```js |
| 109 | +export let one = 1; |
| 110 | +export let two = 2; |
| 111 | +``` |
| 112 | + |
| 113 | +Модуль ниже выведет "1 and 2": |
| 114 | + |
| 115 | +```js |
| 116 | +import {one, two} from "./nums"; |
| 117 | + |
| 118 | +alert( `${one} and ${two}` ); // 1 and 2 |
| 119 | +``` |
| 120 | + |
| 121 | +Импортировать можно и под другим именем, указав его в "as": |
| 122 | + |
| 123 | +```js |
| 124 | +// импорт one под именем item1, а two – под именем item2 |
| 125 | +import {one as item1, two as item2} from "./nums"; |
| 126 | + |
| 127 | +alert( `${item1} and ${item2}` ); // 1 and 2 |
| 128 | +``` |
| 129 | + |
| 130 | +[smart header="Импорт всех значений в виде объекта"] |
| 131 | + |
| 132 | +Можно импортировать все значения сразу в виде объекта вызовом `import * as obj`, например: |
| 133 | + |
| 134 | +```js |
| 135 | +*!* |
| 136 | +import * as numbers from "./nums"; |
| 137 | +*/!* |
| 138 | + |
| 139 | +alert( `${numbers.one} and ${numbers.two}` ); // 1 and 2 |
| 140 | +``` |
| 141 | +[/smart] |
| 142 | + |
| 143 | +## export default |
| 144 | + |
| 145 | +Выше мы видели, что модуль может экспортировать произвольное количество значений при помощи `export`. |
| 146 | + |
| 147 | +Однако, как правило, код стараются организовать так, чтобы каждый модуль делал одну вещь. Иначе говоря, "один файл -- одна сущность, которую он описывает". |
| 148 | + |
| 149 | +Например, файл `user.js` содержит `class User`, файл `login.js` -- функцию `login()` для авторизации, и т.п. |
| 150 | + |
| 151 | +При этом модули, разумеется, будут взаимосвязаны. Например, `login.js`, скорее всего, будет импортировать класс `User` из модуля `user.js`. |
| 152 | + |
| 153 | +Для такой ситуации, когда один модуль экспортирует одно значение, предусмотрено особое ключевое сочетание `export default`. |
| 154 | + |
| 155 | +Если поставить после `export` слово `default`, то значение станет "экспортом по умолчанию". |
| 156 | + |
| 157 | +Такое значение можно импортировать без фигурных скобок. |
| 158 | + |
| 159 | +Например, файл `user.js`: |
| 160 | + |
| 161 | +```js |
| 162 | +*!*export default*/!* class User { |
| 163 | + constructor(name) { |
| 164 | + this.name = name; |
| 165 | + } |
| 166 | +}; |
| 167 | +``` |
| 168 | + |
| 169 | +...А в файле `login.js`: |
| 170 | + |
| 171 | +```js |
| 172 | +import User from './user'; |
| 173 | + |
| 174 | +new User("Вася"); |
46 | 175 | ``` |
47 | 176 |
|
| 177 | +Если бы в `user.js` не было `default`, то в `login.js` необходимо было бы указать фигурные скобки: |
| 178 | + |
| 179 | +```js |
| 180 | +// если в бы user.js не было default: |
| 181 | +// export class User { ... } |
| 182 | + |
| 183 | +// …то при импорте понадобились бы фигурные скобки: |
| 184 | +import {User} from './user'; |
| 185 | + |
| 186 | +new User("Вася"); |
| 187 | +``` |
| 188 | + |
| 189 | +Как видно, "экспорт по умолчанию" -- лишь небольшой синтаксический сахар. Можно было бы и без него, импортировать значение обычным образом через фигурные скобки `{…}`. |
| 190 | + |
| 191 | +Но на практике этот "сахар" весьма приятен, так как позволяет легко видеть, какое именно значение экспортирует модуль, а также обойтись без лишних символов при импорте. |
| 192 | + |
| 193 | +## Использование |
| 194 | + |
| 195 | +Современный стандарт EcmaScript описывает, как импортировать и экспортировать значения из модулей, но он ничего не говорит о том, как эти модули искать, загружать и т.п. |
| 196 | + |
| 197 | +Такие механизмы предлагались в процессе создания стандарта, но были убраны по причине недостаточной проработанности. Возможно, они появятся в будущем. |
| 198 | + |
| 199 | +Сейчас используются системы сборки, как правило, в сочетании с Babel.JS. |
| 200 | + |
| 201 | +Система сборки обрабатывает скрипты, находит в них `import/export` и заменяет их на свои внутренние JavaScript-вызовы. При этом, как правило, много файлов-модулей объединяются в один или несколько скриптов, смотря как указано в конфигурации сборки. |
| 202 | + |
| 203 | +Ниже вы можете увидеть полный пример использования модулей с системой сборки [webpack](http://webpack.github.io). |
| 204 | + |
| 205 | +В нём есть: |
| 206 | +<ul> |
| 207 | +<li>`nums.js` -- модуль, экспортирующий `one` и `two`, как описано выше.</li> |
| 208 | +<li>`main.js` -- модуль, который импортирует `one`, `two` из `nums` и выводит их сумму.</li> |
| 209 | +<li>`webpack.config.js` -- конфигурация для системы сборки.</li> |
| 210 | +<li>`bundle.js` -- файл, который создала система сборки из `main.js` и `nums.js`.</li> |
| 211 | +<li>`index.html` -- простой HTML-файл для демонстрации.</li> |
| 212 | +</ul> |
48 | 213 |
|
49 | 214 | [codetabs src="nums"] |
50 | 215 |
|
51 | 216 |
|
| 217 | +## Итого |
52 | 218 |
|
53 | | -То есть, браузер, в котором есть поддержка модулей, или система сборки ("сегодняшний" вариант) |
| 219 | +Современный стандарт описывает, как организовать код в модули, экспортировать и импортировать значения. |
54 | 220 |
|
55 | | -Модуль -- это файл со специальными командами: |
| 221 | +Экспорт: |
56 | 222 |
|
57 | 223 | <ul> |
58 | | -<li>Экспорты -- </li> |
| 224 | +<li>`export` можно поставить прямо перед объявлением функции, класса, переменной.</li> |
| 225 | +<li>Если `export` стоит отдельно от объявления, то значения в нём указываются в фигурных скобках: `export {…}`.</li> |
| 226 | +<li>Также можно экспортировать "значение по умолчанию" при помощи `export default`.</li> |
| 227 | +</ul> |
| 228 | + |
| 229 | +Импорт: |
| 230 | +<ul> |
| 231 | +<li>В фигурных скобках указываются значения, а затем -- модуль, откуда их брать: `import {a, b, c as d} from "module"`.</li> |
| 232 | +<li>Можно импортировать все значения в виде объекта при помощи `import * as obj from "module"`.</li> |
| 233 | +<li>Без фигурных скобок будет импортировано "значение по умолчанию": `import User from "user"`.</li> |
| 234 | +</ul> |
59 | 235 |
|
| 236 | +На текущий момент модули требуют системы сборки на сервере. Автор этого текста преимущественно использует webpack, но есть и другие варианты. |
60 | 237 |
|
61 | 238 |
|
62 | 239 |
|
63 | 240 |
|
64 | 241 |
|
65 | | -Общее между ними |
66 | 242 |
|
67 | | -Модуль -- способ организации кода по файлам. Каждый файл |
|
0 commit comments