Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Модулі в JavaScript: import/export». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**`export` віддає сутність із модуля назовні, `import` підключає її в іншому файлі, а різниця між `export default` і іменованим `export` у кількості та в іменах: default один на файл і імпортується без фігурних дужок під будь-яким іменем, іменованих може бути скільки завгодно і вони імпортуються в `{}` рівно за своїм іменем.** Обидві форми статичні: зв'язки між модулями відомі ще до виконання коду, тому працюють tree shaking і перевірки збирача, а модуль завантажується й кешується один раз. ```javascript // math.js export const PI = 3.14; // іменований експорт export default function add(a, b) { // експорт за замовчуванням return a + b; } // app.js import sum, { PI } from './math.js'; // default без дужок, іменований у дужках console.log(sum(1, 2), PI); // 3 3.14 ``` **Ключове:** іменованих експортів багато і їхні імена фіксовані, default один і його ім'я довільне.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**`export` віддає змінну, функцію або клас із модуля назовні, а `import` підключає експортовану сутність у іншому файлі.** Разом вони утворюють вбудовану модульну систему, яка з'явилася в ES6 (2015) і дозволяє ділити код на файли-модулі та обмінюватися між ними значеннями, функціями, класами тощо. ## Теорія ### TL;DR - `export` відправляє сутність назовні, `import` завантажує її всередину іншого модуля. - Іменованих експортів у файлі може бути скільки завгодно, імпортують їх у фігурних дужках і рівно за іменем. - `export default` дозволений один на файл, імпортується без дужок і під будь-яким іменем. - Перейменувати можна і на експорті, і на імпорті через `as`, а `import * as ns` збирає весь модуль в один об'єкт. - Імпорти статичні: їх не можна писати всередині `if`, `for` чи функції; для завантаження на вимогу є `await import()`. - Модуль завантажується й кешується один раз, а працює це лише в модульному контексті (`type="module"` в HTML або `.mjs` чи `"type": "module"` у Node.js). ### Швидкий приклад Файл `math.js`: ```javascript export const PI = 3.14; export function add(a, b) { return a + b; } ``` Файл `app.js`: ```javascript import { PI, add } from './math.js'; console.log(PI); // 3.14 console.log(add(2, 3)); // 5 ``` ### Іменований експорт і експорт за замовчуванням **Іменований експорт** (`export`) дозволяє віддати назовні кілька сутностей з одного файлу. ```javascript // math.js export const PI = 3.14; export function multiply(a, b) { return a * b; } ``` Імпортувати їх треба **за іменем**, у фігурних дужках, і імена мають збігатися: ```javascript import { PI, multiply } from './math.js'; ``` **Експорт за замовчуванням** (`export default`) віддає одну головну сутність файлу, найчастіше це «головний» об'єкт, функція або клас. ```javascript // math.js export default function add(a, b) { return a + b; } ``` Імпортувати його можна **під будь-яким іменем** і без фігурних дужок: ```javascript import sum from './math.js'; console.log(sum(2, 3)); // 5 ``` Порівняння двох форм: | Критерій | `export` (іменований) | `export default` | | --- | --- | --- | | Кількість на файл | Скільки завгодно | Тільки один | | Імпорт | У фігурних дужках `{}` | Без фігурних дужок | | Ім'я | Має збігатися | Може бути будь-яким | | Перейменування при імпорті | Через `as` | Просто пишете інше ім'я | | Приклад | `import { add } from './file.js'` | `import add from './file.js'` | Три типові комбінації: ```javascript // math.js: іменований експорт export const PI = 3.14; export function add(a, b) { return a + b; } ``` ```javascript // app.js import { PI, add } from './math.js'; console.log(add(1, 2)); // 3 ``` ```javascript // math.js: експорт за замовчуванням (функція може бути анонімною) export default function(a, b) { return a * b; } ``` ```javascript // app.js import multiply from './math.js'; console.log(multiply(2, 3)); // 6 ``` ```javascript // math.js: змішаний експорт export const PI = 3.14; export default function add(a, b) { return a + b; } ``` ```javascript // app.js import add, { PI } from './math.js'; console.log(add(1, 2), PI); // 3 3.14 ``` ### Перейменування, імпорт усього модуля та реекспорт Перейменувати сутність можна при експорті: ```javascript function sum(a, b) { return a + b; } export { sum as add }; ``` і при імпорті: ```javascript import { add as plus } from './math.js'; plus(2, 3); // 5 ``` Весь модуль можна завантажити одним об'єктом, це зручно, коли експортів багато: ```javascript import * as math from './math.js'; console.log(math.PI); // 3.14 console.log(math.add(2, 3)); // 5 ``` Реекспорт дозволяє одному модулю «переупаковувати» інші, наприклад щоб зробити один вхідний файл для теки: ```javascript // utils.js export { add, multiply } from './math.js'; ``` Тепер споживач бере все з одного місця: ```javascript import { add } from './utils.js'; ``` ### Правила роботи модулів | Особливість | Опис | | --- | --- | | Працює лише в модулях (`type="module"` в HTML або `.mjs` чи `"type": "module"` у Node.js) | Інакше буде `SyntaxError` | | Імпорт і експорт завжди статичні | Їх не можна писати всередині `if`, `for` або функції | | Модулі кешуються | Завантажуються один раз і далі перевикористовуються | | Завантаження модулів асинхронне | Для завантаження на вимогу є `await import()` | | Тіло модуля виконується у strict mode і має власну область видимості | Змінні модуля не потрапляють у глобальний об'єкт | Іменовані імпорти це «живі» зв'язки (live bindings): якщо модуль пізніше змінить експортовану змінну, споживач побачить нове значення, а не копію старого. Динамічний імпорт завантажує модуль на вимогу і повертає проміс: ```javascript const math = await import('./math.js'); console.log(math.add(2, 3)); // 5 ``` Він працює всередині `async`-функції або на верхньому рівні модуля, і саме на ньому будується code splitting. ### ES modules проти CommonJS | Критерій | ES modules (`import` / `export`) | CommonJS (`require` / `module.exports`) | | --- | --- | --- | | Синтаксис | `import x from './m.js'` | `const x = require('./m.js')` | | Коли резолвляться зв'язки | Статично, до виконання | Динамічно, під час виконання | | Де працює | Браузер і Node.js | Історично Node.js | | Завантаження | Асинхронне, є `await import()` | `require` синхронний | | Що дає імпорт | Живі зв'язки на експортовані значення | Копію об'єкта `module.exports` на момент виклику | | Tree shaking | Можливий завдяки статичності | Практично неможливий | ```javascript // CommonJS const { add } = require('./math.js'); module.exports = { add }; // ES modules import { add } from './math.js'; export { add }; ``` ### Підсумок | Ключове слово | Що робить | Приклад | | --- | --- | --- | | `export` | Віддає змінні та функції назовні | `export const PI = 3.14;` | | `export default` | Віддає головну сутність файлу | `export default class User {}` | | `import` | Підключає експортовані сутності | `import { PI } from './math.js';` | Простіше кажучи: > `export` це «віддати назовні», `import` це «завантажити всередину», а `export default` це «віддати одне головне». ### Типові помилки 1. **Забути про модульний контекст.** Звичайний `<script src="app.js">` не розуміє `import`, потрібен `<script type="module" src="app.js">`, а в Node.js розширення `.mjs` або `"type": "module"` у `package.json`. 2. **Плутати дужки.** `import { add } from './math.js'` бере іменований експорт, `import add from './math.js'` бере default. Якщо в модулі немає default, друга форма дасть `undefined` або помилку збирача. 3. **Помилятися в імені іменованого імпорту.** Імена мають збігатися символ у символ; щоб назвати інакше, потрібен `as`: `import { add as plus } from './math.js'`. 4. **Писати кілька `export default` в одному файлі.** Дозволений рівно один, інакше `SyntaxError`. 5. **Ставити `import` усередину умови чи функції.** Статичний імпорт можливий лише на верхньому рівні модуля; для умовного завантаження є `await import()`. 6. **Забувати розширення файлу у відносному шляху.** У браузері та в Node.js з ES modules `'./math'` не працює, треба `'./math.js'`, на відміну від звички з CommonJS і збирачів. 7. **Чекати, що модуль виконається двічі.** Модулі кешуються: скільки б файлів його не імпортувало, тіло модуля відпрацює один раз.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.