Модули: import и export
ES-модули (ESM) — стандартная система разбиения JavaScript-кода на изолированные файлы с явным указанием экспортируемых и импортируемых значений через ключевые слова
exportиimport.
Зачем нужно
До ESM разработчики использовали глобальные переменные или системы вроде CommonJS (require/module.exports). ES-модули позволяют писать чистый, тестируемый код с чёткими зависимостями, избегать конфликтов имён и эффективно применять tree-shaking в бандлерах.
Где используется
- Любой современный фронтенд-проект (React, Vue, Svelte, Vanilla)
- Node.js (
.mjsили"type": "module"вpackage.json) - Браузерный
<script type="module"> - Бандлеры: Webpack, Vite, Rollup, esbuild
Named export (именованный экспорт)
// math.js
export const PI = 3.14159;
export function add(a, b) {
return a + b;
}
export class Vector {
constructor(x, y) { this.x = x; this.y = y; }
length { return Math.sqrt(this.x ** 2 + this.y ** 2); }
}
// main.js
import { PI, add, Vector } from './math.js';
console.log(PI); // 3.14159
console.log(add(2, 3)); // 5
const v = new Vector(3, 4);
console.log(v.length); // 5
Default export (экспорт по умолчанию)
// logger.js
export default class Logger {
log(msg) { console.log(`[LOG] ${msg}`); }
}
// main.js
import Logger from './logger.js'; // имя выбирается произвольно
import MyLogger from './logger.js'; // тоже сработает
const log = new Logger();
log.log('Старт');
Переименование при импорте/экспорте
// Экспорт с псевдонимом
export { add as sum, PI as pi };
// Импорт с псевдонимом
import { sum as addNumbers, pi } from './math.js';
console.log(addNumbers(1, 2)); // 3
Импорт всего модуля
import * as Math from './math.js';
console.log(Math.PI); // 3.14159
console.log(Math.add(1,2)); // 3
Реэкспорт (barrel-файл)
// index.js — «бочка»: объединяет несколько модулей
export { add, PI } from './math.js';
export { default as Logger } from './logger.js';
export * from './utils.js';
// Теперь всё можно импортировать из одного места
import { add, Logger } from './index.js';
Динамический импорт
// Загрузка модуля по условию (lazy loading)
async function loadChart() {
const { Chart } = await import('./chart.js');
return new Chart();
}
// Используется в роутерах, code splitting
button.addEventListener('click', async () => {
const module = await import('./heavyModule.js');
module.run;
});
Подключение в HTML
<script type="module" src="./main.js"></script>
<!-- или inline -->
<script type="module">
import { greet } from './greet.js';
greet('World');
</script>
Особенности ESM
- Строгий режим (
'use strict') включён автоматически thisна верхнем уровне равенundefined(неwindow)- Модули выполняются один раз и кешируются
- Поддерживают цикличные зависимости (но с осторожностью)
Частые ошибки
1. Смешение default и named без скобок
// logger.js: export default Logger
import Logger from './logger.js'; // OK — default
import { Logger } from './logger.js'; // undefined — нет named export с таким именем
2. Расширение .js обязательно в браузере и Node ESM
import { add } from './math'; // ошибка в браузере и Node (ESM)
import { add } from './math.js'; // правильно
3. Изменение live binding
// counter.js
export let count = 0;
export function increment() { count++; }
import { count, increment } from './counter.js';
console.log(count); // 0
increment;
console.log(count); // 1 — импорт это «живая» ссылка, не копия